配置 Orchestrator

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

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

编排器分布式配置图

图 1. 编排器配置图。

与车辆无关的配置不会因 OEM 或车辆而异。每个 OEM 的所有车辆上的配置都保持不变。不同 OEM 的不同车辆上的车辆专属配置可能会有所不同,但特定 OEM 制造的所有车辆的配置可能相同。

配置 APEX

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

每个虚拟机配置

Orchestrator 启动时,会加载并解析虚拟机配置(如果存在)。此配置文件的绝对路径通过系统属性 persist.sdv.orchestrator_config_path 和 ro.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 后,此属性不会在后续启动时覆盖它。

您可以使用 bootconfig 或内核 cmdline 设置 ro.boot.sdv.orchestrator_config_path。

文件格式

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

配置语法

本部分介绍了配置语法。

服务套餐

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

  • 借助 InstanceToGroupMapping,您可以在组中添加服务包的实例,以在同一服务包的实例之间建立依赖关系。

  • InstancesStates 定义服务包实例的不同状态。

  • InstancesStateConfiguration 定义了如果条件的计算结果为 true,则必须将服务包实例设置为的状态(来自 InstancesStates)。

  • ServiceBundleConfig 包含有关特定服务包及其实例的信息。它包含相应 bundle 的 InstanceToGroupMapping 和 InstancesStateConfiguration。

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

必需的 bundle 配置

捆绑包配置至少提供以下属性:

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

    instance: "instance_1"
    instance: "instance_n"
}

此声明定义了 n 个服务包实例,每个实例都有各自的 FQIN:

vm_name.package_name.service_bundle_name.instance_1
…
vm_name.package_name.service_bundle_name.instance_n

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

配置实例

声明服务包实例没有任何效果。如需由 Orchestrator 执行,必须配置实例。例如,必须告知 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;
}

虚拟机级配置

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

Orchestrator 不保证状态更改的执行顺序。Orchestrator 会将每个实例提升到给定状态。

通过在任何配置部分中使用 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 执行,必须配置群组。例如,必须告知 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;
}

配置状态

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

条件

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

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

  • (可选)没有条件的配置状态始终处于活跃状态,这意味着其求值结果为 true

实例状态和群组状态

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

重试配置

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

  • max_retries:定义 Orchestrator 在发生暂时性故障或收到软件包崩溃通知后重试转换的次数。在操作成功或处理新模式后,重试计数器会重置为 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 的重启和重试逻辑可妥善管理多种故障场景:

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

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

  • 暂时性错误(SERVICE_NOT_FOUND、OPERATION_FAILED、INTERNAL_ERROR):Orchestrator 会重试操作,而不会执行任何特殊清理操作。
  • 持续性错误(VALUE_CORRUPTED、INVALID_ARGUMENT):Orchestrator 会假定服务软件包可能处于损坏状态,并尝试终止服务实例,然后再重试操作,以确保干净重启。
  • 永久性错误 (PERMISSION_DENIED):系统不会重试该操作,并且该 bundle 会被视为处于不可恢复的状态。

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

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

向健康监测器报告状态

Orchestrator 会公开一个内部 Binder 接口,Health Monitor (HM) 会注册到该接口,以便持续接收有关所有服务包状态的更新。通过此接口,Orchestrator 会主动报告以下两项内容:

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

系统会报告所有实例(包括未注册为心跳监控的实例)的这些信息。HM 会使用这些信息来实现其 API,以报告虚拟机的状态。如需了解详情,请参阅健康状况监控。

示例

本部分提供了配置带条件的状态的示例。

基础服务示例
  • 没有条件,因此始终处于有效状态。
  • 启动单个服务实例。
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 时处于有效状态。

    此状态可视为节能状态。

  • 将一个与 HVAC 相关的服务实例声明为 destroyed。

  • 在此示例中,当 SYSTEM_POWER_LOW 和 RANGE_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. Orchestration Engine:此服务会读取该属性,以确定 Orchestrator 可以对 Lifecycle Manager 进行多少次并发调用(例如 startService、stopService)。这对于启动和模式转换期间的性能至关重要,因为在这些期间,许多 bundle 可能会同时更改状态。

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

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

配置方法

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

BOARD_BOOTCONFIG += \
    androidboot.sdv.max_bundles_management_threads=8

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

启动时间优化

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

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

性能

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

  1. 服务包注册表:首先启动,以加载所有服务包元数据。
  2. Lifecycle Manager 和 Orchestrator:这些核心代理会在注册表准备就绪后立即启动。这种提前启动至关重要,因为它使 Orchestrator 能够开始评估其配置,并准备立即启动服务包。
  3. 其他 SDV 代理:仅在 Orchestrator 准备就绪后启动。

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

Orchestrator 消耗的模式

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

  • sdv.orchestrator.bootup.power_mode.ready

  • sdv.orchestrator.bootup.vehicle_mode.ready

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

车辆和电源状态

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

自定义模式

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

功能:

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

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

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

    • 值:自定义模式的当前状态,如果未设置任何值,则可以为 UNDEFINED。

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

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

  • 验证责任:OEM 负责确保状态转换有效。Orchestrator 接受任何新值。

预估特征:

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

  • 预计用时:模式不会定期发送。相反,模式是事件驱动的,由特定操作触发,例如开门、启动停车序列、启动充电周期以及其他具有 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;
}

根据模式配置 bundle

现有的 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 示例

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

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。然后,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 正在执行电源模式更新,则会请求取消正在进行的模式。虽然 Lifecycle Manager 本身不支持取消正在进行的转换,但 Orchestrator 会验证是否没有发起新的服务包请求。

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

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

如果 Orchestrator 正在处理非电源模式更新,并且要执行的模式队列中存在电源请求,则电源转换会从队列中移除。这会阻止其执行。

示例:使用上一个示例中的配置,如果 Orchestrator 正在处理与电源无关的更新(例如车辆更新),并且 SUSPEND_TO_RAM_ENTER 位于队列中,则收到 SHUTDOWN_CANCELLED 会导致所有实例(instance-1、instance-2、instance-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 的输出相结合,可以全面了解虚拟机中服务包的生命周期。