Orchestrator konfigurieren

Der Orchestrator ist ein lokaler SDV-Agent, der auf jeder VM ausgeführt wird und einen Mechanismus zur Steuerung des Erstellens, Startens, Beendens oder Löschens von Dienst-Bundles bietet. Dies erfolgt über eine Orchestrierungskonfiguration, in der Sie eine Reihe von Regeln definieren, die festlegen, wann und wie Aktionen für Servicebündelinstanzen ausgeführt werden. Diese Regeln basieren auf Fahrzeug-, Energie- und benutzerdefinierten Modi.

Sie können den Orchestrator in Konfigurations-APEX-Dateien oder über Konfigurationen pro VM konfigurieren. Dieses verteilte Konfigurationssystem ermöglicht es, Teile jedes Dienstpakets unabhängig über die Service Bundle Registry zu aktualisieren, wie hier dargestellt.

Diagramm der verteilten Orchestrator-Konfiguration

Abbildung 1. Diagramm der Orchestrator-Konfiguration.

Fahrzeugunabhängige Konfigurationen ändern sich nicht je nach OEM oder Fahrzeug. Die Konfiguration bleibt bei allen Fahrzeugen des jeweiligen OEM gleich. Fahrzeugspezifische Konfigurationen können sich je nach Fahrzeug und OEM unterscheiden. Die Konfiguration kann jedoch für alle Fahrzeuge eines bestimmten OEM gleich sein.

Konfigurations-APEX-Module

Zur Laufzeit ruft der Orchestrator aus der Service-Bundle-Registrierung eine SDV-Orchestrierung für jedes Service-Bundle ab und lädt und parst jede Konfiguration. Weitere Informationen finden Sie unter Orchestrierungsmetadaten.

Pro VM-Konfiguration

Wenn der Orchestrator startet, wird die VM-Konfiguration (falls vorhanden) geladen und geparst. Der absolute Pfad zu dieser Konfigurationsdatei wird über die Systemattribute persist.sdv.orchestrator_config_path und ro.boot.sdv.orchestrator_config_path angegeben.

Das System bestimmt den Pfad der VM-Konfigurationsdatei beim Booten anhand der folgenden Hierarchie:

  1. Das System prüft das Attribut persist.sdv.orchestrator_config_path. Wenn er einen Wert hat, wird dieser Pfad verwendet. Dieser Wert wird auch nach einem Neustart beibehalten oder zur Laufzeit festgelegt.

  2. Wenn persist.sdv.orchestrator_config_path leer ist, prüft das System die Eigenschaft ro.boot.sdv.orchestrator_config_path. Wenn das Attribut ro.boot.sdv einen Wert hat, wird dieser Pfad in das Attribut „persist“ kopiert und für den aktuellen und alle zukünftigen Starts verwendet, sofern er nicht überschrieben wird.

persist.sdv.orchestrator_config_path

persist.sdv.orchestrator_config_path ist die primäre Eigenschaft, die vom SDV Orchestrator-Agent verwendet wird, um den Pfad zu seiner Konfigurationsdatei abzurufen. Dies ist eine dauerhafte Eigenschaft. Ihr Wert wird also auch nach einem Neustart des Geräts gespeichert. Sie können den Wert zur Laufzeit ändern. Das ist nützlich für Tests oder bestimmte Szenarien, z. B. Ende-zu-Ende-Tests.

Sie können den Wert zur Laufzeit mit dem Befehl setprop und zur Build-Zeit mit einer Makefile-Datei (mit der Erweiterung .mk) oder einer Ressourcenscriptdatei mit der Erweiterung .rc festlegen.

Attribut zur Laufzeit festlegen

Das Attribut zur Laufzeit festzulegen ist nützlich für Tests oder vorübergehende Änderungen, da der Wert über Neustarts hinweg gespeichert wird:

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

Attribut zur Build-Zeit festlegen

Wenn Sie diese Property als Teil der Build-Konfiguration Ihres Geräts festlegen möchten, fügen Sie der Make-Datei Ihres Produkts oder Boards eine Zeile hinzu. Das ist ideal, um einen Standardwert für ein neues Gerätebild festzulegen.

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

Sie können diese Eigenschaft auch in einer Ressourcenscriptdatei festlegen:

# 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 ist ein schreibgeschütztes Attribut, das beim Booten verwendet wird, um einen Anfangswert für das Attribut persist.sdv.orchestrator_config_path bereitzustellen. Wenn persist.sdv.orchestrator_config_path beim Systemstart leer ist, wird der Wert von ro.boot.sdv.orchestrator_config_path dorthin kopiert. Sobald persist.sdv.orchestrator_config_path festgelegt wurde, wird es bei nachfolgenden Starts nicht durch diese Property überschrieben.

Sie können ro.boot.sdv.orchestrator_config_path über die Bootkonfiguration oder die Kernel-Befehlszeile festlegen.

Dateiformat

Definieren Sie die Orchestrierungskonfiguration im .textproto-Format (z. B. in strukturiertem Text), damit neue Konfigurationen zur Laufzeit geladen werden können.

Konfigurationssyntax

In diesem Abschnitt wird die Konfigurationssyntax beschrieben.

Dienstpakete

Jedes Dienstbündel muss mit der Dienstbündelkonfiguration definiert werden. Diese identifiziert das Bündel im Orchestrator und wird verwendet, um den Lebenszyklus der Bündelinstanz zu verwalten. Die Konfiguration des Dienstbündels definiert Folgendes:

  • Mit InstanceToGroupMapping können Sie eine Instanz des Dienstpakets in eine Gruppe einfügen, um Abhängigkeiten zwischen Instanzen desselben Dienstpakets herzustellen.

  • InstancesStates definiert die verschiedenen Status für die Dienstpaketinstanz.

  • InstancesStateConfiguration definiert den Status (aus InstancesStates), auf den eine Dienstbündelinstanz gesetzt werden muss, wenn die Bedingung als true ausgewertet wird.

  • ServiceBundleConfig enthält Informationen zum jeweiligen Service-Bundle und seinen Instanzen. Es enthält für das Bundle die entsprechenden InstanceToGroupMapping und InstancesStateConfiguration.

  • CustomModes definiert eine Liste benutzerdefinierter Modi, die für das Bundle veröffentlicht werden dürfen. CustomModes wird verwendet, um zu verhindern, dass ein nicht autorisiertes Bundle den Wert eines benutzerdefinierten Modus ändert. Dieses Feld ist optional, da das Service-Bundle möglicherweise nicht in einem benutzerdefinierten Modus veröffentlicht wird. Weitere Informationen

Erforderliche Bundle-Konfiguration

Die Bundle-Konfiguration enthält mindestens die folgenden Attribute:

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

    instance: "instance_1"
    instance: "instance_n"
}

In dieser Deklaration werden n-Servicebundle-Instanzen mit den entsprechenden FQINs definiert:

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

Der VM-Name ist in der Konfiguration nicht explizit deklariert. Da die Konfiguration pro VM definiert wird, ist der VM-Name immer der Name der VM, auf der die Konfigurationsdatei bereitgestellt wird, und dem Orchestrierungs-Agent bereits bekannt.

Instanzen konfigurieren

Die Deklaration von Dienstpaketinstanzen hat keine Auswirkungen. Damit Instanzen vom Orchestrator ausgeführt werden können, müssen sie konfiguriert sein. Der Orchestrator muss beispielsweise darüber informiert werden, unter welchen Bedingungen (oder welchem Status der VM oder des Fahrzeugs) eine Instanz ausgeführt werden soll. Konfigurationsstatus für Instanzen sollten über Folgendes definiert werden:

  • condition ist ein Ausdruck für den VM- oder Fahrzeugstatus, der ausgewertet werden soll.

  • instances_states ist eine Reihe von Status pro Instanz, die angewendet werden sollen, wenn die Bedingung true ergibt.

Weitere Informationen finden Sie unter Bedingungen.

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

Zuordnung von Instanzen zu Gruppen

Sie können Dienstinstanzen auch konfigurieren, indem Sie sie in Dienstgruppen einfügen. Auf der Ebene der Dienstpaketkonfiguration können Sie Gruppen Instanzen hinzufügen. Anschließend können Sie Gruppen auf VM-Konfigurationsebene konfigurieren. Weitere Informationen finden Sie im nächsten Abschnitt und unter Dienstpakete.

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

Hier ein Beispiel für ein Protoschema:

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

Konfiguration auf VM-Ebene

Mit der VM-Konfiguration können Sie Gruppenzuordnungen und die Konfiguration für Gruppen definieren. Damit lassen sich Abhängigkeiten zwischen Dienstpaketen auf VM-Ebene modellieren. So können Sie den Status mehrerer Dienstpakete gleichzeitig ändern. Alle Instanzen einer Gruppe werden in den angegebenen Status versetzt.

Der Orchestrator garantiert nicht die Reihenfolge, in der die Statusänderung ausgeführt wird. Der Orchestrator sorgt dafür, dass jede Instanz den angegebenen Status erreicht.

Gruppen werden implizit deklariert, indem der Name group in einem der Konfigurationsteile verwendet wird. Dazu gehören beispielsweise die Zuordnung von Instanzen zu Gruppen, die Zuordnung von Gruppen zu Gruppen und die Konfigurationsstatus von Gruppen.

Gruppen-zu-Gruppen-Zuordnung

Gruppen können andere Gruppen enthalten. Indem wir deklarieren, dass group_1 subgroup_2 enthält, fügen wir alle Dienstinstanzen aus subgroup_2 zu group_1 hinzu.

Beispiel:

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

Gruppe konfigurieren

Das Deklarieren einer Gruppe hat keine Auswirkungen. Damit Gruppen vom Orchestrator ausgeführt werden können, müssen sie konfiguriert werden. Der Orchestrator muss beispielsweise darüber informiert werden, unter welchen Bedingungen oder in welchem Zustand der VM oder des Fahrzeugs die Gruppen ausgeführt werden sollen.

Sie können Gruppen auf ähnliche Weise wie Dienstinstanzen konfigurieren, nämlich mithilfe von Konfigurationsstatus. Der einzige Unterschied ist die Verwendung von groups_states anstelle von instances_states in der Syntax:

state {
    condition {
        power_state: "ON"
    }

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

Proto-Schema

Hier ein Beispiel für ein Proto-Schema:

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

Konfigurationsstatus

Konfigurationsstatus (Status) definieren, wann eine Dienstinstanz oder ‑gruppe gestartet, beendet oder zerstört wird. Sie bestehen aus conditions und instances_states (Bundle-Konfiguration) sowie groups_states (VM-Konfiguration).

Bedingungen

Mit Bedingungen kann dem Modell eine boolesche Bedingung mitgeteilt werden, unter der der definierte Instanzstatus angewendet wird, wenn sie als true ausgewertet wird. Eine Bedingung hat folgende Merkmale:

  • Beliebig komplexer boolescher Ausdruck (gebildet mit and- oder not-Ausdrücken) basierend auf unterstützten Signalen wie Stromversorgung, Fahrzeug und benutzerdefiniertem Modus.

  • (Optional) Der Konfigurationsstatus ohne Bedingung ist immer aktiv, d. h., er wird als true ausgewertet.

Instanzstatus und Gruppenstatus

instances_states und groups_states haben die folgenden Eigenschaften.

  • Geben Sie an, welche Zustände der Orchestrierungs-Agent für die angegebenen Instanzen oder Gruppen benötigt, wenn der Zustand active ist.

  • Wenn Sie einen Status auf die Gruppe anwenden, gilt er für jede Dienstpaketinstanz in der Gruppe. Es gibt keine bestimmte Reihenfolge, in der Instanzen in diesen Status versetzt werden.

Folgende Bundesstaaten werden unterstützt:

  • started nach dem Aufruf von Service::on_start.

  • created

    • nachdem Service::new aufgerufen wurde, aber bevor Service::on_start aufgerufen wird.

      ODER

    • nachdem Service::on_stop aufgerufen wurde, aber bevor Service::drop aufgerufen wird.

  • destroyed nach dem Aufruf von Service::drop.

Regelsatz

Der Konfigurationsstatus kann je nach Bedingung entweder aktiv oder inaktiv sein. Es können jederzeit mehrere Status aktiv sein. Wenn ein Orchestrierungs-Agent eine Signalaktualisierung empfängt, werden alle Konfigurationsstatus ausgewertet, bevor der Lebenszyklus von Service-Bundles geändert wird. Dienstinstanzstatus werden gemäß diesen Regeln ausgewertet:

  • Wenn keiner der aktiven Status auf die Dienstinstanz zutrifft, wird sie zerstört.

  • Wenn ein oder mehrere aktive Status zutreffen, gilt folgende Priorität:

    1. destroyed hat absolute Priorität.
    2. started hat Vorrang vor created.

Proto-Schema

Hier ein Beispiel für ein Proto-Schema:

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

Strategie für die Wiederherstellung nach einem Absturz und den Neustart

Der Orchestrator bietet einen robusten Mechanismus zur Behandlung von Abstürzen von Dienstbündeln und Fehlern bei der Lebenszyklusumstellung. Da der Orchestrator einen ganzheitlichen Überblick über die Dienststatus hat und Modusübergänge verwaltet, ist er die am besten geeignete Komponente für die Ausführung der Neustart- und Wiederholungsstrategie. Der Lifecycle Manager (LM) meldet Abstürze des Service-Bundles über Binder-Death-Benachrichtigungen an den Orchestrator. Um unnötige Binder-Aufrufe an den LM zu vermeiden, speichert der Orchestrator den letzten Status jedes Bundles im Cache (unabhängig davon, ob er erfolgreich war oder nicht) und wendet keine Übergänge noch einmal an, wenn der letzte bekannte Status mit dem neuen angeforderten Status übereinstimmt.

Konfiguration wiederholen

Sie können die Neustart- und Wiederholungsstrategie pro Instanz in Ihrer Orchestrator-Konfiguration mit retry_mapping definieren. Wenn max_retries in der Konfiguration nicht festgelegt ist, wird der Standardwert aus der Systemeigenschaft ro.boot.sdv.orchestrator.recovery.max_retries übernommen. Wenn diese Eigenschaft nicht festgelegt ist, wird der Wert standardmäßig auf 0 gesetzt.

  • max_retries: Definiert, wie oft der Orchestrator einen Übergang nach einem vorübergehenden Fehler oder einer Benachrichtigung über einen Bundle-Absturz wiederholt. Der Zähler für Wiederholungsversuche wird nach einem erfolgreichen Vorgang oder bei der Verarbeitung eines neuen Modus auf den Wert von max_retries zurückgesetzt. Wenn mehrere Zuordnungen auf dieselbe Instanz ausgerichtet sind, hat die mit dem höchsten max_retries Vorrang.

Beispielkonfiguration

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

Verhalten bei der Wiederherstellung

Die Neustart- und Wiederholungslogik des Orchestrators kann mehrere Fehlerszenarien problemlos verarbeiten:

  • Absturz im Normalbetrieb: Wenn ein Dienst-Bundle während der Ausführung abstürzt, wendet der Orchestrator die Neustartstrategie an und versucht, das Bundle basierend auf den verbleibenden Wiederholungsversuchen in den zuletzt angeforderten Zustand zurückzubringen.
  • Absturz während des Modusübergangs: Wenn ein Bundle beim Erzwingen eines neuen Modus abstürzt, wird die Neustartanfrage in die Warteschlange gestellt und später verarbeitet. Sobald die Anfrage verarbeitet wurde, prüft der Orchestrator, welcher der letzte Status der Instanz war, und wendet den Neustart nur an, wenn sich die Instanz nicht im letzten angeforderten Status (aus dem letzten Modusübergang) befindet.
  • Neuer Modus während der Wiederherstellung: Wenn der Orchestrator eine Anfrage zum Wechsel in einen neuen Modus erhält, während ein Bundle neu gestartet wird (oder sich in der Warteschlange der neu zu startenden Instanzen befindet), wird die laufende Wiederherstellung abgebrochen. Der neue Modusübergang wird übernommen und der Zähler für Wiederholungsversuche wird zurückgesetzt, um eine neue Reihe von Versuchen für den neuen Zielstatus zu ermöglichen.

Der Orchestrator unterscheidet zwischen verschiedenen Fehlertypen, die vom Lifecycle Manager zurückgegeben werden, um die Wiederholungsstrategie zu bestimmen:

  • Vorübergehende Fehler (SERVICE_NOT_FOUND, OPERATION_FAILED, INTERNAL_ERROR): Der Orchestrator wiederholt den Vorgang, ohne dass spezielle Bereinigungsmaßnahmen erforderlich sind.
  • Schwerwiegende Fehler (VALUE_CORRUPTED, INVALID_ARGUMENT): Der Orchestrator geht davon aus, dass sich das Dienstbündel in einem beschädigten Zustand befindet, und versucht, die Dienstinstanz zu beenden, bevor er den Vorgang noch einmal ausführt, um einen sauberen Neustart zu gewährleisten.
  • Permanente Fehler (PERMISSION_DENIED): Der Vorgang wird nicht wiederholt und das Bundle befindet sich in einem nicht wiederherstellbaren Zustand.

Wenn der Lifecycle Manager abstürzt, gehen alle Service-Bundle-Prozesse verloren. Da der tatsächliche Status unbekannt ist, macht der Orchestrator jede Instanz ungültig und wendet eine Neustartstrategie mit verbleibenden Wiederholungsversuchen an, um jede Instanz in den zuletzt angeforderten Status zu versetzen.

Um endlose Wiederholungsschleifen für Bundles zu verhindern, die wiederholt abstürzen oder fehlschlagen, wird der Zähler für Wiederholungsversuche erst nach einem erfolgreichen Lebenszyklusvorgang oder bei einer neuen Modusübergangsanfrage auf max_retries zurückgesetzt. Wenn ein Bundle aufgrund aufeinanderfolgender Fehler (z. B. ein Übergangsfehler gefolgt von einem Absturz) alle Wiederholungsversuche aufgebraucht hat, wird es erst neu gestartet, wenn der Wiederholungszähler zurückgesetzt wurde.

Statusberichte an Health Monitor

Der Orchestrator stellt eine interne Binder-Schnittstelle zur Verfügung, bei der sich der Health Monitor (HM) registriert, damit er kontinuierliche Updates zum Status aller Dienstpakete erhält. Über diese Schnittstelle meldet der Orchestrator aktiv Folgendes:

  • Lebenszyklusstatus:Der beabsichtigte Status der Instanz basierend auf der aktuellen Konfiguration und den aktiven Modi (z. B. „Gestartet“, „Erstellt“ oder „Zerstört“).
  • Wiederherstellungsstatus:Der Status des Erreichens des beabsichtigten Lebenszyklusstatus. Er gibt an, ob die Instanz betriebsbereit ist, derzeit nach einem Fehler wiederholt wird oder die Wiederherstellung nach Erschöpfung aller Wiederholungsversuche fehlgeschlagen ist.

Diese Informationen werden für alle Instanzen gemeldet, auch für solche, die nicht für die Heartbeat-Überwachung registriert sind. HM verwendet diese Informationen, um seine APIs zu implementieren und den Status der VM zu melden. Weitere Informationen findest du unter Health Monitoring.

Beispiele

In diesem Abschnitt finden Sie Beispiele für die Konfiguration von Status mit Bedingungen.

Beispiel für Basisdienst
  • Hat keine Bedingung und ist daher immer aktiv.
  • Startet eine einzelne Dienstinstanz.
state {
  # Note: This state has no condition, hence its actions are valid throughout the lifetime of the program
  instances_states { started: "ServiceBundleName" }
}
HLK-App-Beispiel
  • Bedingung: Aktiv, wenn custom_state != occupancy.OCCUPANCY_EMPTY || custom_state == preheat.PREHEAT_ON.

  • Deklariert mehrere HLK-bezogene Dienstinstanzen als 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"
  }
}
Beispiel für Energiesparmodus
  • Bedingung: Aktiv, wenn custom_state == system_power.SYSTEM_POWER_LOW && custom_state == range_ext.RANGE_EXT_ON.

    Dieser Status kann als Energiesparmodus betrachtet werden.

  • Deklariert eine HLK-bezogene Dienstinstanz als destroyed.

  • Wenn in diesem Beispiel die Modi SYSTEM_POWER_LOW und RANGE_EXT_ON aktiv sind, wird die HLK-App ohne die Dienstinstanz RefrigerantLoop ausgeführt:

    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" }
    }
    
Beispiel für das Leben an Bord
  • Bedingung: Aktiv, wenn power_state == ON && vehicle_state == LIFE_ON_BOARD.

    Dieser Status kann als Jemand ist im Auto und das Auto ist eingeschaltet angesehen werden.

  • Gibt an, dass Temperatursensoren ausgeführt werden.

  • Wenn sich jemand im Auto befindet, werden Elemente wie die Temperatur aus Sicherheitsgründen überwacht.

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

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

Beispiele

In diesem Abschnitt finden Sie vollständige Beispiele mit:

  • Eine Proto-Konfiguration auf Service-Bundle-Ebene, in der ein Service-Bundle mit zwei Instanzen eingeführt wird, die jeweils Teil einer Gruppe sind

  • Eine Proto-Konfiguration auf VM-Ebene, die Logik für die Interaktion mit den Gruppen basierend auf Modi enthält.

Konfiguration auf Service-Bundle-Ebene

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

Konfiguration auf VM-Ebene

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

Parallelität der Paketverwaltung konfigurieren

Die System-Property ro.boot.sdv.max_bundles_management_threads ist ein wichtiger Abstimmungsparameter, um die Leistung und den Ressourcenverbrauch während der Lebenszyklusvorgänge des Service-Bundles zu steuern. Sie definiert die maximale Parallelität für Transaktionen von Service-Bundles und wirkt sich direkt auf zwei Hauptdienste aus:

  1. Orchestration Engine:Dieser Dienst liest die Property, um zu ermitteln, wie viele gleichzeitige Aufrufe (z. B. startService, stopService) der Orchestrator an den Lifecycle Manager senden kann. Dies ist entscheidend für die Leistung beim Starten und bei Modusübergängen, bei denen sich der Status vieler Bundles gleichzeitig ändern kann.

  2. Lifecycle Manager:Dieser Dienst verwendet den Wert der Property, um die Größe des Binder-Thread-Pools zu berechnen, der für die Verarbeitung aller eingehenden Anfragen zuständig ist. So wird sichergestellt, dass das Sprachmodell genügend Threads hat, um die gleichzeitigen Anfragen des Orchestrators zu verarbeiten.

Wenn diese Property nicht festgelegt ist, wird für beide Dienste standardmäßig der Wert 12 verwendet.

Konfigurationsmethode

Sie können das Attribut in der Datei BoardConfig.mk Ihres Geräts festlegen, indem Sie es der Variablen BOARD_BOOTCONFIG hinzufügen. So wird sichergestellt, dass der Wert bei jedem Start des Geräts angewendet wird.

BOARD_BOOTCONFIG += \
    androidboot.sdv.max_bundles_management_threads=8

Wenn Sie den Wert für Ihr Gerät ändern möchten, passen Sie diese Zeile in der entsprechenden BoardConfig.mk-Datei an und führen Sie den Build noch einmal aus.

Optimierung der Startzeit

Die ro.sdv.orchestrator.state.ready ist eine boolesche write-once-Property, die Teil einer Strategie zur Leistungsoptimierung beim Booten ist. Dies weist darauf hin, dass der Orchestration-Agent die Initialisierung abgeschlossen hat und bereit ist, den Lebenszyklus von Service-Bundles zu verwalten. Der Hauptzweck besteht darin, den Start des Orchestrators und seiner verwalteten Dienstbündel zu priorisieren, indem die Startreihenfolge anderer SDV-Agents gesteuert wird.

  • Festgelegt von:Orchestration-Agent.
  • Wann:Einmal während der Bootsequenz.
  • Verwendung:Diese Eigenschaft wird vom Init-System verwendet, um die Startsequenz der meisten SDV-Agents zu steuern (Updates Manager, VSIDL-Anbieter, Health Monitor, Service Discovery, Data Tunnel, RPC, VPM und Telemetrie). Wenn der Orchestrator frühzeitig gestartet wird und andere KI-Agenten auf diese Eigenschaft warten, kann der Orchestrator seine wichtige Aufgabe, Dienstbündel zu starten, ohne Konkurrenz um Systemressourcen beginnen.

Leistung

Wenn alle Agents gleichzeitig beim Systemstart gestartet werden, kann es zu Ressourcenkonflikten kommen, die den gesamten Startvorgang verlangsamen. Um dieses Problem zu beheben, wird eine sequenzielle Startreihenfolge mithilfe von Systemattributen erzwungen:

  1. Service-Bundle-Registrierung:Hier werden zuerst alle Metadaten von Service-Bundles geladen.
  2. Lifecycle Manager und Orchestrator:Diese Core-Agents werden gestartet, sobald die Registry bereit ist. Dieser frühe Start ist entscheidend, da der Orchestrator so seine Konfiguration auswerten und sich darauf vorbereiten kann, Dienstbündel sofort zu starten.
  3. Andere SDV-Agents:Werden erst gestartet, wenn der Orchestrator bereit ist.

Diese kontrollierte Sequenz sorgt dafür, dass der Orchestrator Priorität hat, Systemressourcen zu verwenden, um Dienstpakete so schnell wie möglich zu starten. Dies führt zu einem schnelleren, deterministischeren und effizienteren Systemstart.

Vom Orchestrator verwendete Modi

Der Orchestrierungs-Agent unterhält ein aktives Abo für Fahrzeug- und Energiemodi, die vom VPM übertragen werden. Wenn die erste Verbindung zwischen dem Orchestrator und dem VPM-System (Vehicle and Power Management) hergestellt wird, legt der Orchestrator die folgenden booleschen Systemeigenschaften auf true fest:

  • sdv.orchestrator.bootup.power_mode.ready

  • sdv.orchestrator.bootup.vehicle_mode.ready

Anhand einer Konfigurationsdatei berechnet der Orchestrierungs-Agent dynamisch die Gruppe von Service-Bundles, die sich basierend auf den aktuellen Werten der empfangenen Modi in einem laufenden Zustand befinden sollten. Der Orchestrator kommuniziert dann mit dem Lifecycle Manager und gibt verschiedene Befehle aus, um den tatsächlichen Status von Service-Bundles mit dem berechneten Zielstatus abzugleichen.

Fahrzeug- und Energiestatus

Der VPM-Agent (Vehicle Mode and Power Management) informiert SDV-Komponenten über den aktuellen Status des Fahrzeugs, z. B. den Betriebsmodus (z. B. „Parken“ oder „Fahren“) und den Energiestatus (z. B. „Ein“ und „Stand-by“). Der Orchestrator wertet diese Werte aus, um anhand der Orchestrator-Konfiguration festzulegen, welche Service-Bundles ausgeführt werden sollen. Weitere Informationen finden Sie unter Fahrzeug- und Energieverwaltung.

Benutzerdefinierte Modi

Angesichts der Vielzahl an Fahrzeugmodi können wir nicht alle modellieren. Jeder OEM hat unterschiedliche Anforderungen und die Standardisierung von Fahrzeugmodi kann nicht alle OEM-Anwendungsfälle abdecken. Daher unterstützen wir OEM-spezifische Modi, die als benutzerdefinierte Modi bezeichnet werden. Diese Modi erweitern die vorhandenen Fahrzeug- und Energiemodi nicht. Stattdessen bieten sie eine Möglichkeit, neue Modi zu definieren.

Funktionen:

  • Globaler Bereich:Benutzerdefinierte Modi sind global und gelten einheitlich für alle VMs, die vom Orchestrator verwaltet werden.

  • Zusammensetzung:Jede benutzerdefinierte Modusänderung besteht aus zwei Elementen:

    • Name:Eindeutige Kennung, die vom OEM zur Darstellung des benutzerdefinierten Modus ausgewählt wurde.

    • Wert:Der aktuelle Status für den benutzerdefinierten Modus. Wenn kein Wert festgelegt ist, kann er UNDEFINED sein.

  • Orchestrator-Rolle:Der Orchestrator fungiert als passiver Empfänger von Werten für den benutzerdefinierten Modus.

  • Rolle des Dienstleistungspakets:Jedes Dienstleistungspaket kann mehrere benutzerdefinierte Modi haben und neue Werte für jeden Modus veröffentlichen. Mehrere Service-Bundles können denselben benutzerdefinierten Modus haben. Das bedeutet, dass ein benutzerdefinierter Modus neue Werte aus verschiedenen Quellen empfangen kann.

  • Verantwortung für die Validierung:OEMs sind für die Validierung von Statusübergängen verantwortlich. Der Orchestrator akzeptiert jeden neuen Wert.

Geschätzte Merkmale:

  • Geschätzte Anzahl:Der Lebenszyklus der meisten Service-Bundles wird durch Energie- und Fahrzeugmodi verwaltet. Benutzerdefinierte Modi spielen dabei eine ergänzende Rolle. Wir gehen davon aus, dass die Anzahl der benutzerdefinierten Modi im zweistelligen Bereich liegt und nicht im dreistelligen.

  • Geschätzte Dauer:Modi werden nicht regelmäßig gesendet. Stattdessen sind Modi ereignisgesteuert und werden durch bestimmte Aktionen ausgelöst, z. B. durch das Öffnen einer Tür, das Einleiten einer Parksequenz, das Starten eines Ladezyklus und andere ähnliche Ereignisse von OEM-definierter Bedeutung.

Das Design des benutzerdefinierten Modus bietet die Flexibilität, bestimmte Modi zu definieren und zu verwalten, während der Orchestrator unabhängig von der zugrunde liegenden Zustandsautomatenlogik bleibt.

Unterstützte Modi

Damit Dienstbündel nur in benutzerdefinierten Modi veröffentlicht werden, die ihnen gehören, muss jedes Dienstbündel die Liste der benutzerdefinierten Modi, die ihm gehören, explizit in seiner Orchestrator-Konfiguration deklarieren. Diese ist in der lokalen VM mit der Dienstbündelregistrierung verfügbar. Versuche, in einem nicht deklarierten benutzerdefinierten Modus zu veröffentlichen, werden verworfen.

Um die benutzerdefinierten Modi zu deklarieren, die ein Dienstpaket veröffentlichen darf (und somit besitzt), wird das service_bundle_config-Protoschema um Folgendes erweitert:

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

Pakete basierend auf Modi konfigurieren

Die vorhandene Orchestrator-Proto-Konfiguration (die Condition-Komponente) unterstützt die Bearbeitung von Dienst-Bundles basierend auf benutzerdefinierten Modi:

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

Das folgende Beispiel zeigt, wie Instanzen eines Dienst-Bundles konfiguriert werden, damit sie basierend auf dem Status TURN und FOG gestartet werden:

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

}

Neue benutzerdefinierte Modi festlegen

Das Festlegen eines neuen benutzerdefinierten Moduswerts beginnt mit dem Service-Bundle, das den gewünschten Wert an den lokalen Orchestrator auf derselben VM übermittelt. Der Orchestrator prüft dann, ob das Dienstpaket die Berechtigungen hat, die für die Veröffentlichung im angegebenen benutzerdefinierten Modus erforderlich sind. Dazu wird die in .textproto definierte Konfiguration herangezogen, um festzustellen, ob der Wert an andere VMs weitergegeben werden soll. Nach der Weitergabe prüft jeder Orchestrator seine Konfiguration, um die Liste der Service-Bundles zu finden, für die der Status geändert werden soll.

RPC

Jeder Orchestrator, der auf jeder VM ausgeführt wird, erstellt einen RPC-Server, um auf neue benutzerdefinierte Moduswerte zu warten. Für jedes Dienstpaket, das einen benutzerdefinierten Modus aktualisieren möchte, muss ein RPC-Client für den Server erstellt werden. ACLs werden erzwungen, um zu verhindern, dass nicht autorisierte Bundles eine Verbindung zum Server herstellen.

Die Protobuf-Definition zum Festlegen eines neuen Werts über RPC sieht so aus:

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

Abbrechen von Stromübergängen

Der Orchestrator ermöglicht das Abbrechen laufender Energieübergänge über den SHUTDOWN_CANCELLED-Energiemodus (der vom VPM an den Orchestrator gesendet wird).

Betrachten Sie die folgende Orchestrator-Konfiguration als Beispiel:

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

Wenn ein SHUTDOWN_CANCELLED-Modus empfangen wird, hängt das Verhalten des Orchestrators von zwei primären Szenarien ab. In beiden Fällen wird der SHUTDOWN_CANCELLED-Energiesparmodus am Ende der Warteschlange angehängt. SHUTDOWN_CANCELLED wird dann ausgeführt, nachdem die Elemente in der Warteschlange verarbeitet wurden.

Szenario 1: Der aktuelle Modus ist ein Energiesparmodus

Wenn der Orchestrator ein Update des Energiemodus ausführt, wird eine Abbrechen-Anfrage für den laufenden Modus gesendet. Der Lifecycle Manager unterstützt das Abbrechen einer laufenden Umstellung nicht direkt, der Orchestrator prüft jedoch, dass keine neuen Service-Bundle-Anfragen initiiert werden.

Beispiel: Wenn instance-1 aus der Konfiguration im vorherigen Beispiel gerade gestartet wird, wenn der Modus SHUTDOWN_CANCELLED empfangen wird, wird der Start von instance-1 abgeschlossen. instance-2 und instance-3 werden jedoch nicht in den Status „Gestartet“ überführt.

Szenario 2: Ein Energiemodus ist in der Verarbeitungswarteschlange vorhanden

Wenn der Orchestrator ein Update für einen Nicht-Energiesparmodus verarbeitet und sich in der Warteschlange der auszuführenden Modi eine Energieanfrage befindet, wird der Energieübergang aus der Warteschlange entfernt. Dadurch wird die Ausführung verhindert.

Beispiel: Wenn der Orchestrator mit der Konfiguration aus dem vorherigen Beispiel an einem Update arbeitet, das nicht mit der Stromversorgung zusammenhängt (z. B. einem Fahrzeugupdate), und SUSPEND_TO_RAM_ENTER in der Warteschlange steht, führt der Empfang von SHUTDOWN_CANCELLED dazu, dass keine der Instanzen (instance-1, instance-2, instance-3) gestartet wird.

Implementierungsbeispiel

Der Katalog für einen Client, der mit Middleware generierten Code verwenden möchte, um einen Client für den RPC-Server zu erstellen, kann so aussehen:

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

Wenn Sie Code generieren, müssen Sie die Abhängigkeit dem Orchestrator-Katalog hinzufügen:

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

Der Clientcode zum Senden eines neuen Werts sieht so aus:

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

Tools zur Fehlerbehebung

Der Orchestrator-Agent unterstützt das dumpsys-Tool. Sie können es aufrufen, indem Sie den folgenden Befehl für eine laufende SDV-Instanz ausführen:

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

Mit diesem Tool können Sie den internen Status des Orchestrator-Agents debuggen und analysieren. Dadurch wird Folgendes angezeigt:

  • Aktueller Modus:Hier sehen Sie den aktiven Fahrzeug-, Energie- und benutzerdefinierten Modus.
  • Publisher im benutzerdefinierten Modus:Hier sehen Sie, welche Dienste benutzerdefinierte Modi veröffentlichen können und in welchen Modi.
  • Erforderlicher Status pro Dienst:Hier erfahren Sie den Status der einzelnen Dienstpakete basierend auf vordefinierten Bedingungen und aktuellen Modi. So lässt sich herausfinden, warum ein Dienst möglicherweise nicht den erwarteten Status hat.
  • Status der Erzwingung des Modus:Hier sehen Sie den Status eines laufenden erzwungenen Modus oder den letzten erzwungenen Modus, falls keiner läuft.
  • Warteschlange für die Erzwingung von Modi:Hier sehen Sie die Modi, die erzwungen werden sollen.

Beispiel:

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

Weitere Informationen zu einzelnen Dienst-Bundles, die vom Orchestrator verwaltet werden, erhalten Sie mit dem vorhandenen dumpsys aus dem Lifecycle Manager:

dumpsys google.sdv.lifecycle.ILifecycleManager/default

So erhalten Sie detaillierte Informationen zum Lebenszyklusstatus der einzelnen Dienste. Wenn Sie die Orchestrator-dumpsys-Ausgabe mit der Ausgabe von Lifecycle Manager kombinieren, erhalten Sie ein vollständiges Bild des Lebenszyklus der Dienst-Bundles in der VM.