Configura el organizador

El Orchestrator es un agente de SDV local que se ejecuta en cada máquina virtual (VM) y proporciona un mecanismo para controlar cuándo se deben crear, iniciar, detener o destruir los paquetes de servicios. Esto se hace a través de una configuración de organización, en la que defines un conjunto de reglas que determinan cuándo y cómo se realizan las acciones en las instancias del paquete de servicios. Estas reglas se basan en los modos de vehículo, energía y personalizado.

Puedes configurar el orquestador en APEX de configuración o a través de configuraciones por VM. Este sistema de configuración distribuido permite que las partes de cada paquete de servicios se actualicen de forma independiente a través del registro de paquetes de servicios, como se ilustra aquí.

Diagrama de configuración distribuida del orquestador

Figura 1: Diagrama de configuración del orquestador.

Las configuraciones independientes del vehículo no cambian según el OEM o el vehículo. La configuración sigue siendo la misma en todos los vehículos de cada OEM. Las configuraciones específicas del vehículo pueden diferir en distintos vehículos de diferentes OEM, aunque la configuración podría ser la misma para todos los vehículos fabricados por un OEM específico.

APEX de configuración

En el tiempo de ejecución, el orquestador va al registro de paquetes de servicios para recuperar una orquestación de SDV para cada paquete de servicios, y carga y analiza cada configuración. Para obtener más información, consulta Metadatos de orquestación.

Configuración por VM

Cuando se inicia el orquestador, carga y analiza la configuración de la VM (si está presente). La ruta de acceso absoluta a este archivo de configuración se especifica a través de las propiedades del sistema persist.sdv.orchestrator_config_path y ro.boot.sdv.orchestrator_config_path.

El sistema determina la ruta de acceso del archivo de configuración de la VM durante el inicio según la siguiente jerarquía:

  1. El sistema verifica la propiedad persist.sdv.orchestrator_config_path. Si tiene un valor, se usa esa ruta de acceso. Este valor persiste en los reinicios o se establece en el tiempo de ejecución.

  2. Si persist.sdv.orchestrator_config_path está vacío, el sistema verifica la propiedad ro.boot.sdv.orchestrator_config_path. Si la propiedad ro.boot.sdv tiene un valor, esa ruta se copia en la propiedad persist y se usa para el arranque actual y todos los arranques futuros (a menos que se anule).

persist.sdv.orchestrator_config_path

persist.sdv.orchestrator_config_path es la propiedad principal que usa el agente de SDV Orchestrator para obtener la ruta de acceso a su archivo de configuración. Esta es una propiedad persistente, lo que significa que su valor se guarda en todos los reinicios del dispositivo. Puedes cambiar el valor en el tiempo de ejecución, lo que resulta útil para las pruebas o situaciones específicas (por ejemplo, pruebas de extremo a extremo).

Puedes establecer el valor en el tiempo de ejecución con el comando setprop y en el tiempo de compilación con un archivo makefile (con la extensión .mk) o un archivo de secuencia de comandos de recursos, con la extensión .rc.

Cómo establecer la propiedad en el tiempo de ejecución

Establecer la propiedad en el tiempo de ejecución es útil para probar o realizar cambios temporales, ya que el valor se guarda en los reinicios:

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

Establece la propiedad en el momento de la compilación

Para establecer esta propiedad como parte de la configuración de compilación de tu dispositivo, agrega una línea al archivo makefile de tu producto o placa. Es ideal para establecer un valor predeterminado para una nueva imagen del dispositivo.

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

También puedes establecer esta propiedad en un archivo de secuencia de comandos de recursos:

# 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 es una propiedad de solo lectura que se usa en el momento del inicio para proporcionar un valor inicial para la propiedad persist.sdv.orchestrator_config_path. Si persist.sdv.orchestrator_config_path está vacío cuando se inicia el sistema, se copia el valor de ro.boot.sdv.orchestrator_config_path. Una vez que se establece persist.sdv.orchestrator_config_path, esta propiedad no lo reemplazará en los inicios posteriores.

Puedes establecer ro.boot.sdv.orchestrator_config_path con bootconfig o la línea de comandos del kernel.

Formato de archivo

Define la configuración de orquestación en formato .textproto (por ejemplo, en texto estructurado) para que se puedan cargar configuraciones nuevas en el tiempo de ejecución.

Sintaxis de configuración

En esta sección, se describe la sintaxis de configuración.

Paquetes de servicios

Cada paquete de servicios debe definirse con la configuración del paquete de servicios, que identifica el paquete dentro del orquestador y se usa para controlar el ciclo de vida de la instancia del paquete. La configuración del paquete de servicios define lo siguiente:

  • InstanceToGroupMapping te permite incluir una instancia del paquete de servicios en un grupo para establecer dependencias entre instancias del mismo paquete de servicios.

  • InstancesStates define los diferentes estados de la instancia del paquete de servicios.

  • InstancesStateConfiguration define el estado (de InstancesStates) en el que se debe establecer una instancia de paquete de servicio si la condición se evalúa como true.

  • ServiceBundleConfig contiene información sobre el paquete de servicios específico y sus instancias. Contiene, para el paquete, los respectivos InstanceToGroupMapping y InstancesStateConfiguration.

  • CustomModes define una lista de modos personalizados que se permiten publicar en el paquete. CustomModes se usa para evitar que un paquete no autorizado modifique el valor de un modo personalizado. Este campo es opcional, ya que es posible que el paquete de servicios no se publique en ningún modo personalizado. Para obtener más información, consulta Modos personalizados.

Configuración obligatoria del paquete

Como mínimo, la configuración del paquete proporciona estos atributos:

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

    instance: "instance_1"
    instance: "instance_n"
}

Esta declaración define instancias del paquete de servicios n con los FQIN respectivos:

vm_name.package_name.service_bundle_name.instance_1

vm_name.package_name.service_bundle_name.instance_n

El nombre de la VM no se declara de forma explícita en la configuración. Dado que la configuración se define por VM, el nombre de la VM siempre es el de la VM en la que se implementa el archivo de configuración y el agente de orquestación ya lo conoce.

Configura las instancias

La declaración de instancias de paquetes de servicios no tiene efecto. Para que el orquestador ejecute las instancias, estas deben configurarse. Por ejemplo, se debe informar al orquestador sobre las condiciones (o el estado de la VM o el vehículo) en las que se debe ejecutar una instancia. Para configurar instancias, los estados de configuración se deben definir de la siguiente manera:

  • condition es una expresión sobre el estado de la VM o del vehículo que se debe evaluar.

  • instances_states es un conjunto de estados por instancia que se deben aplicar si la condición se evalúa como true.

Para obtener más información, consulta Condiciones.

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"
        }
    }
}

Asignación de instancias a grupos

También puedes configurar instancias de servicio incluyéndolas en grupos de servicios. A nivel de la configuración del paquete de servicios, puedes agregar instancias a grupos. Luego, puedes configurar grupos a nivel de la configuración de la VM. Para obtener más información, consulta la siguiente sección y Paquetes de servicios.

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"
    }
}

Esquema de .proto

A continuación, se muestra un ejemplo de esquema de .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;
}

Configuración a nivel de la VM

La configuración de la VM permite definir asignaciones de grupos y la configuración de grupos. Se usa para modelar las dependencias entre los paquetes de servicios a nivel de la VM, lo que brinda flexibilidad para modificar el estado de varios paquetes de servicios al mismo tiempo. Todas las instancias de un grupo se llevan al estado especificado.

El orquestador no garantiza el orden en el que se ejecuta el cambio de estado. El orquestador promueve cada instancia para que se encuentre en el estado determinado.

Los grupos se declaran de forma implícita usando el nombre group en cualquiera de las partes de la configuración. Por ejemplo, la asignación de instancias a grupos, la asignación de grupos a grupos y los estados de configuración de grupos.

Asignación de grupo a grupo

Los grupos pueden contener otros grupos. Cuando declaramos que group_1 contiene subgroup_2, agregamos de manera efectiva todas las instancias de servicio de subgroup_2 a group_1.

Por ejemplo:

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

Configura un grupo

Declarar un grupo no tiene ningún efecto. Para que el orquestador los ejecute, se deben configurar los grupos. Por ejemplo, se debe informar al orquestador en qué condiciones o estado de la VM o el vehículo se deben ejecutar los grupos.

Puedes configurar grupos de manera similar a las instancias de servicio, es decir, usando estados de configuración. La única diferencia es el uso de groups_states en lugar de instances_states en la sintaxis:

state {
    condition {
        power_state: "ON"
    }

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

Esquema de .proto

A continuación, se muestra un esquema de .proto de ejemplo:

// 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;
}

Estados de configuración

Los estados de configuración (estados) definen cuándo se inicia, detiene o destruye una instancia o un grupo de servicios, y constan de conditions y instances_states (configuración del paquete) y groups_states (configuración de la VM).

Condiciones

Las condiciones permiten que el modelo tenga una condición booleana según la cual, cuando se evalúa como true, se aplica el estado de instancia definido. Una condición tiene las siguientes características:

  • Expresión booleana arbitrariamente compleja (formada con expresiones and o not) basada en indicadores admitidos, como potencia, vehículo y modo personalizado.

  • (Opcional) El estado de configuración sin una condición siempre está activo, lo que significa que se evalúa como true.

Estados de instancias y estados de grupos

instances_states y groups_states tienen estas características.

  • Indica qué estados necesita el agente de orquestación para aplicar a las instancias o los grupos determinados, dado que el estado es active.

  • Cuando se aplica un estado al grupo, este se aplica a cada instancia del paquete de servicios del grupo. No se aplica ningún orden en cuanto al momento en que las instancias se llevan al estado.

Entre los estados admitidos, se incluyen los siguientes:

  • started después de que se llama a Service::on_start.

  • created

    • después de que se llama a Service::new, pero antes de que se llame a Service::on_start.

      O

    • después de que se llama a Service::on_stop, pero antes de que se llame a Service::drop.

  • destroyed después de que se llama a Service::drop.

Conjunto de reglas

Un estado de configuración puede ser activo o inactivo, según la condición. Varios estados pueden estar activos en cualquier momento. Cuando un agente de orquestación recibe una actualización de la señal, se evalúan todos los estados de configuración antes de modificar el ciclo de vida de los paquetes de servicios. Los estados de las instancias de servicio se evalúan según estas reglas:

  • Cuando ninguno de los estados activos se aplica a la instancia de servicio, esta se destruye.

  • Cuando se aplican uno o más estados activos, se aplica la siguiente precedencia:

    1. destroyed tiene prioridad absoluta.
    2. started tiene prioridad sobre created.

Esquema de .proto

A continuación, se muestra un esquema de .proto de ejemplo:

// 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;
}

Estrategia de recuperación y reinicio ante fallas

El Orchestrator proporciona un mecanismo sólido para controlar las fallas del paquete de servicios y los errores de transición del ciclo de vida. Dado que el orquestador tiene una vista integral de los estados del servicio y administra las transiciones de modo, es el componente más adecuado para ejecutar la estrategia de reinicio y reintento. El paquete de servicios de Lifecycle Manager (LM) informa las fallas al Orchestrator a través de notificaciones de muerte del binder. Para evitar llamadas innecesarias del vinculador al LM, el orquestador almacena en caché el último estado de cada paquete (ya sea exitoso o no) y no vuelve a aplicar transiciones si el último estado conocido es el mismo que el nuevo solicitado.

Configuración de reintentos

Puedes definir la estrategia de reinicio y reintento por instancia en la configuración del orquestador con retry_mapping. Si max_retries no está configurado, el valor predeterminado se toma de la propiedad del sistema ro.boot.sdv.orchestrator.recovery.max_retries. Si no se establece esta propiedad, el valor recurre a 0.

  • max_retries: Define la cantidad de veces que Orchestrator reintenta una transición después de una falla transitoria o una notificación de falla del paquete. El contador de reintentos se restablece al valor de max_retries después de una operación exitosa o cuando se procesa un modo nuevo. Si varias asignaciones segmentan la misma instancia, tiene prioridad la que tenga el valor de max_retries más alto.

Ejemplo de configuración

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
    }
  }
}

Comportamiento de recuperación

La lógica de reintento y reinicio del organizador administra con facilidad varias situaciones de falla:

  • Falla de funcionamiento normal: Si un paquete de servicios falla mientras se ejecuta, el orquestador aplica la estrategia de reinicio y trata de que el paquete vuelva a su último estado solicitado según los reintentos restantes.
  • Falla durante la transición de modo: Si un paquete falló mientras se aplicaba un modo nuevo, la solicitud de reinicio se pone en cola y se procesa más tarde. Una vez que se procesa la solicitud, el orquestador verifica cuál fue el último estado de la instancia y solo aplica el reinicio si la instancia no se encuentra en el último estado solicitado (desde la última transición de modo).
  • Nuevo modo durante la recuperación: Si el orquestador recibe una solicitud para cambiar a un modo nuevo mientras se reinicia un paquete (o está en la cola de instancias para reiniciar), cancela la recuperación en curso. La nueva transición de modo se hace cargo, y el contador de reintentos se restablece para permitir un nuevo conjunto de intentos para el nuevo estado objetivo.

Orchestrator distingue entre los diferentes tipos de errores que devuelve Lifecycle Manager para determinar la estrategia de reintento:

  • Errores transitorios (SERVICE_NOT_FOUND, OPERATION_FAILED, INTERNAL_ERROR): El orquestador vuelve a intentar la operación sin realizar ninguna acción especial de limpieza.
  • Errores persistentes (VALUE_CORRUPTED, INVALID_ARGUMENT): El orquestador supone que el paquete de servicio podría estar en un estado dañado y trata de detener la instancia del servicio antes de volver a intentar la operación para garantizar un reinicio limpio.
  • Errores permanentes (PERMISSION_DENIED): No se vuelve a intentar la operación y se considera que el paquete está en un estado irrecuperable.

Si el Lifecycle Manager falla, se pierden todos los procesos del paquete de servicio. Dado que se desconoce el estado real, Orchestrator invalida cada instancia y aplica una estrategia de reinicio con los reintentos restantes para llevar cada instancia al último estado solicitado.

Para evitar bucles de recuperación infinitos en el caso de los paquetes que fallan o se bloquean de forma reiterada, el contador de reintentos solo se restablece a max_retries después de que se completa una operación de ciclo de vida o cuando se solicita una nueva transición de modo. Si un paquete agota sus reintentos debido a fallas consecutivas (por ejemplo, una falla de transición seguida de una falla), no se reinicia hasta que se restablece el contador de reintentos.

Informes de estado para el supervisor de estado

Orchestrator expone una interfaz de vinculador interna a la que se registra Health Monitor (HM), lo que le permite recibir actualizaciones continuas sobre el estado de todos los paquetes de servicios. A través de esta interfaz, el organizador informa de forma activa lo siguiente:

  • Estado del ciclo de vida: Es el estado previsto de la instancia según la configuración actual y los modos activos (como iniciada, creada o destruida).
  • Estado de recuperación: Es el estado de alcanzar el estado del ciclo de vida previsto, que indica si la instancia está operativa, si se está reintentando después de una falla o si no se pudo recuperar después de agotar todos los reintentos.

Esta información se registra para todas las instancias, incluidas las que no se registraron para la supervisión de latidos. El HM usa esta información para implementar sus APIs y, así, informar el estado de la VM. Puedes obtener más información en Monitoreo de la salud.

Ejemplos

En esta sección, se presentan ejemplos para configurar estados con condiciones.

Ejemplo de servicio básico
  • No tiene condición y, por lo tanto, siempre está activo.
  • Inicia una sola instancia de servicio.
state {
  # Note: This state has no condition, hence its actions are valid throughout the lifetime of the program
  instances_states { started: "ServiceBundleName" }
}
Muestra de la app de HVAC
  • Condición: Activo cuando custom_state != occupancy.OCCUPANCY_EMPTY || custom_state == preheat.PREHEAT_ON.

  • Declara varias instancias de servicio relacionadas con el HVAC como 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"
  }
}
Ejemplo de ahorro de energía
  • Condición: Activo cuando custom_state == system_power.SYSTEM_POWER_LOW && custom_state == range_ext.RANGE_EXT_ON.

    Este estado se puede considerar como un estado de ahorro de energía.

  • Declara una instancia de servicio relacionada con el HVAC como destroyed.

  • En este ejemplo, cuando los modos SYSTEM_POWER_LOW y RANGE_EXT_ON están activos, la app de HVAC se ejecuta sin la instancia del servicio 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" }
    }
    
Muestra de la vida a bordo
  • Condición: Activo si es power_state == ON && vehicle_state == LIFE_ON_BOARD.

    Este estado se puede ver como Alguien está en el auto y el auto está encendido.

  • Declara que los sensores de temperatura están en funcionamiento.

  • Cuando hay alguien en el automóvil, se supervisan elementos como la temperatura por motivos de seguridad.

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

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

Ejemplos

En esta sección, se presentan ejemplos completos que contienen lo siguiente:

  • Es una configuración de .proto a nivel de paquete de servicios que presenta un paquete de servicios con dos instancias, cada una de las cuales forma parte de un grupo.

  • Es una configuración de .proto a nivel de la VM que introduce lógica para interactuar con los grupos según los modos.

Configuración a nivel del paquete de servicios

# 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"
    }
}

Configuración a nivel de la VM

# 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"
    }
}

Configura el paralelismo de la administración de paquetes

La propiedad del sistema ro.boot.sdv.max_bundles_management_threads es un parámetro de ajuste clave para controlar el rendimiento y el consumo de recursos durante las operaciones del ciclo de vida del paquete de servicios. Define el nivel máximo de paralelismo para las transacciones de paquetes de servicios y afecta directamente a dos servicios principales:

  1. Motor de orquestación: Este servicio lee la propiedad para determinar cuántas llamadas simultáneas (por ejemplo, startService, stopService) puede realizar el orquestador al administrador del ciclo de vida. Esto es fundamental para el rendimiento durante el inicio y las transiciones de modo en los que muchos paquetes pueden cambiar de estado simultáneamente.

  2. Lifecycle Manager: Este servicio usa el valor de la propiedad para calcular el tamaño de su grupo de subprocesos de Binder, que es responsable de controlar todas las solicitudes entrantes. Esto garantiza que el LM tenga suficientes subprocesos para controlar las solicitudes simultáneas del orquestador.

Si no se establece esta propiedad, ambos servicios se establecen de forma predeterminada en un valor de 12.

Método de configuración

Puedes establecer la propiedad en el archivo BoardConfig.mk de tu dispositivo agregándola a la variable BOARD_BOOTCONFIG. Esto garantiza que el valor se aplique cada vez que se inicie el dispositivo.

BOARD_BOOTCONFIG += \
    androidboot.sdv.max_bundles_management_threads=8

Para cambiar el valor de tu dispositivo, modifica esta línea en el archivo BoardConfig.mk correspondiente y vuelve a compilar.

Optimización del tiempo de inicio

ro.sdv.orchestrator.state.ready es una propiedad booleana write-once que forma parte de una estrategia de optimización del rendimiento durante el inicio. Indica que el agente de orquestación completó su inicialización y está listo para comenzar a administrar el ciclo de vida de los paquetes de servicios. Su propósito principal es priorizar el inicio del orquestador y sus paquetes de servicios administrados controlando la secuencia de inicio de otros agentes de SDV.

  • Establecido por: El agente de organización.
  • Cuándo: Una vez durante la secuencia de inicio.
  • Uso: El sistema init usa esta propiedad para controlar la secuencia de inicio de la mayoría de los agentes de SDV (Updates Manager, proveedor de VSIDL, Health Monitor, Service Discovery, Data Tunnel, RPC, VPM y Telemetry). Al iniciar el Orchestrator con anticipación y hacer que otros agentes esperen esta propiedad, el sistema garantiza que el Orchestrator pueda comenzar su tarea crítica de iniciar paquetes de servicios sin competir por los recursos del sistema.

Rendimiento

Durante el inicio del sistema, iniciar todos los agentes de forma simultánea puede generar contención de recursos, lo que ralentiza el proceso de inicio general. Para mitigar este efecto, se aplica un orden de inicio secuencial con propiedades del sistema:

  1. Registro de paquetes de servicios: Se inicia primero para cargar todos los metadatos de los paquetes de servicios.
  2. Lifecycle Manager y Orchestrator: Estos agentes principales se inician en cuanto el registro está listo. Este inicio anticipado es fundamental, ya que permite que el orquestador comience a evaluar su configuración y a prepararse para iniciar paquetes de servicios de inmediato.
  3. Otros agentes de SDV: Solo se inician después de que el orquestador esté listo.

Esta secuencia controlada garantiza que el orquestador tenga prioridad para usar los recursos del sistema y, así, iniciar los paquetes de servicios lo antes posible, lo que permite que el sistema se inicie de forma más rápida, determinística y eficiente.

Modos que consume el Orchestrator

El agente de organización mantiene una suscripción activa a los modos de energía y del vehículo que transmite el VPM. Cuando se establece la conexión inicial entre el Orchestrator y el sistema de administración de energía y del vehículo (VPM), el Orchestrator establece las siguientes propiedades booleanas del sistema en true:

  • sdv.orchestrator.bootup.power_mode.ready

  • sdv.orchestrator.bootup.vehicle_mode.ready

Con un archivo de configuración como referencia, el agente de orquestación calcula de forma dinámica el conjunto de paquetes de servicios que deben estar en estado de ejecución según los valores actuales de los modos recibidos. Luego, el orquestador se comunica con el administrador del ciclo de vida y emite diferentes comandos para alinear el estado real de los paquetes de servicios con el estado objetivo calculado.

Estados de alimentación y del vehículo

El agente de administración de energía y modo del vehículo (VPM) permite que los componentes del SDV reciban información sobre el estado actual del vehículo, como el modo operativo (por ejemplo, en estacionamiento o conducción) y el estado de energía (por ejemplo, encendido y suspendido). El orquestador evalúa estos valores para definir qué paquetes de servicios deben ejecutarse según la configuración del orquestador. Para obtener más información, consulta Administración del vehículo y la energía.

Modos personalizados

Dado que hay muchos, no podemos modelar todos los modos de vehículos. Cada OEM tiene necesidades diferentes, y la estandarización de los modos del vehículo no puede abordar todos los casos de uso de los OEM. Como resultado, admitimos modos específicos del OEM, conocidos como modos personalizados. Estos modos no extienden los modos de energía y vehículo existentes. En cambio, proporcionan una forma de definir modos nuevos.

Funcionalidad:

  • Alcance global: Los modos personalizados son globales y se aplican de manera uniforme en todas las VMs administradas por el orquestador.

  • Composición: Cada cambio de modo personalizado consta de dos elementos:

    • Nombre: Es el identificador único que selecciona el OEM para representar el modo personalizado.

    • Valor: Es el estado actual del modo personalizado, que puede ser UNDEFINED cuando no se establece ningún valor.

  • Rol de Orchestrator: El rol de Orchestrator actúa como receptor pasivo de los valores del modo personalizado.

  • Rol de paquete de servicios: Cada paquete de servicios puede tener varios modos personalizados y publicar valores nuevos en cualquiera de ellos. Varios paquetes de servicios pueden tener el mismo modo personalizado, lo que significa que un modo personalizado puede recibir valores nuevos de diferentes fuentes.

  • Responsabilidad de validación: Los OEM son responsables de garantizar transiciones de estado válidas. El orquestador acepta cualquier valor nuevo.

Características estimadas:

  • Recuento estimado: Los modos de energía y vehículo administran el ciclo de vida de la mayoría de los paquetes de servicios, y los modos personalizados desempeñan un papel complementario. Esperamos que el orden de magnitud de los modos personalizados sea de decenas y no de cientos.

  • Momento estimado: Los modos no se envían periódicamente. En cambio, los modos se basan en eventos y se activan por acciones específicas, como abrir una puerta, iniciar una secuencia de estacionamiento, comenzar un ciclo de carga y otros eventos similares de importancia definida por el OEM.

El diseño del modo personalizado proporciona la flexibilidad necesaria para definir y administrar modos específicos, al mismo tiempo que permite que el orquestador permanezca independiente de la lógica subyacente de la máquina de estados.

Modos compatibles

Para garantizar que los paquetes de servicios solo se publiquen en los modos personalizados que poseen, cada uno debe declarar explícitamente la lista de modos personalizados propios dentro de su configuración de Orchestrator, que está disponible en la VM local con el registro de paquetes de servicios. Se descartan los intentos de publicar en un modo personalizado no declarado.

Para declarar los modos personalizados que un paquete de servicios puede publicar (y, por lo tanto, posee), el esquema .proto service_bundle_config se extiende con lo siguiente:

// 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;
}

Configura paquetes según los modos

La configuración existente del proto de Orchestrator (el componente Condition) admite la manipulación de paquetes de servicios según modos personalizados:

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;
}

Muestra de .proto

En el siguiente ejemplo, se muestra cómo configurar instancias de un paquete de servicios para que se inicien según un estado TURN y 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"
    }
}

}

Cómo establecer nuevos modos personalizados

El proceso de configuración de un nuevo valor de modo personalizado comienza con el paquete de servicio, que comunica el valor deseado al Orchestrator local que se ejecuta en la misma VM. Luego, el orquestador verifica que el paquete de servicio tenga los permisos necesarios para publicar en el modo personalizado especificado, y hace referencia a la configuración definida en .textproto para determinar si debe propagar el valor a otras VMs. Una vez propagado, cada Orchestrator revisa su configuración para encontrar la lista de paquetes de servicios para los que se debe cambiar el estado.

RPC

Cada Orchestrator que se ejecuta en cada VM crea un servidor RPC para escuchar los nuevos valores del modo personalizado. Cada paquete de servicios que desee actualizar un modo personalizado debe crear un cliente de RPC para el servidor. Se aplican ACL para evitar que los paquetes no autorizados se conecten al servidor.

La definición de .proto para establecer un valor nuevo a través de RPC se ve como en el siguiente ejemplo:

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) {};
}

Cancelación de transiciones de energía

El Orchestrator permite cancelar las transiciones de energía en curso a través del modo de energía SHUTDOWN_CANCELLED (que el VPM envía al Orchestrator).

Considera la siguiente configuración de Orchestrator como ejemplo:

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

Cuando se recibe un modo SHUTDOWN_CANCELLED, hay dos situaciones principales que determinan el comportamiento del orquestador. En ambos casos, el modo de energía SHUTDOWN_CANCELLED se agrega al final de la fila. Luego, SHUTDOWN_CANCELLED se ejecuta después de que se consumen los elementos en cola.

Situación 1: El modo en curso actual es un modo de energía

Si el Orchestrator está ejecutando una actualización del modo de energía, se solicita la cancelación del modo en curso. Si bien el Administrador del ciclo de vida no admite de forma inherente la cancelación de una transición en curso, el orquestador verifica que no se inicien nuevas solicitudes de paquetes de servicios.

Ejemplo: Si instance-1 de la configuración del ejemplo anterior está en proceso de inicio cuando se recibe el modo SHUTDOWN_CANCELLED, instance-1 completa su inicio. Sin embargo, instance-2 y instance-3 no continúan con sus transiciones al estado iniciado.

Situación 2: Existe un modo de energía en la cola de procesamiento

En el caso de que el orquestador esté procesando una actualización que no sea del modo de energía y haya una solicitud de energía en la cola de modos que se ejecutarán, se quitará la transición de energía de la cola. Esto impide su ejecución.

Ejemplo: Con la configuración del ejemplo anterior, si el orquestador está trabajando en una actualización no relacionada con la energía (como una actualización del vehículo) y SUSPEND_TO_RAM_ENTER está en la cola, recibir SHUTDOWN_CANCELLED no inicia ninguna de las instancias (instance-1, instance-2, instance-3).

Ejemplo de implementación

El catálogo de un cliente que desea usar código generado por el middleware para crear un cliente para el servidor de RPC puede verse como en este ejemplo:

# 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"
    }
}

Cuando generes código, debes agregar la dependencia al catálogo de Orchestrator:

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

El código del cliente para enviar un valor nuevo se ve de la siguiente manera:

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

Herramientas de depuración

El agente de Orchestrator admite la herramienta dumpsys. Puedes invocarlo ejecutando el siguiente comando en una instancia de SDV en ejecución:

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

Usa esta herramienta para depurar y obtener información sobre el estado interno del agente de Orchestrator. Si lo haces, se mostrará lo siguiente:

  • Estado actual de los modos: Consulta los modos activos del vehículo, de energía y personalizados.
  • Publicadores de modos personalizados: Identifican qué servicios pueden publicar modos personalizados (y en qué modos).
  • Estado requerido por servicio: Conoce el estado de cada paquete de servicios según las condiciones predefinidas y los modos actuales. Esto ayuda a diagnosticar por qué un servicio podría no estar en el estado esperado.
  • Estado del modo de aplicación forzosa: Obtén una imagen clara de un modo de aplicación forzosa en curso o del último modo de aplicación forzosa si no hay ninguno en curso.
  • Mode Enforcement Queue: Consulta los modos que están en espera para aplicarse.

Por ejemplo:

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: []
----------------

Para obtener más información sobre los paquetes de servicios individuales que administra Orchestrator, usa el volcado existente de dumpsys de Lifecycle Manager de la siguiente manera:

dumpsys google.sdv.lifecycle.ILifecycleManager/default

Si lo haces, se proporcionará información detallada sobre el estado del ciclo de vida de cada servicio. La combinación del resultado de dumpsys de Orchestrator con el resultado de Lifecycle Manager presenta un panorama completo del ciclo de vida de los paquetes de servicios en la VM.