Konfigurowanie aranżera

Orchestrator to lokalny agent SDV, który działa na każdej maszynie wirtualnej i zapewnia mechanizm kontroli tworzenia, uruchamiania, zatrzymywania i usuwania pakietów usług. Odbywa się to za pomocą konfiguracji orkiestracji, w której określasz zestaw reguł decydujących o tym, kiedy i jak wykonywane są działania na instancjach pakietu usług. Te reguły są oparte na trybach pojazdu, zasilania i niestandardowych.

Orchestratora możesz skonfigurować w konfiguracjach APEX lub za pomocą konfiguracji poszczególnych maszyn wirtualnych. Ten rozproszony system konfiguracji umożliwia niezależne aktualizowanie poszczególnych części każdego pakietu usług za pomocą rejestru pakietów usług, jak pokazano na ilustracji.

Diagram rozproszonej konfiguracji aranżera

Rysunek 1. Diagram konfiguracji aranżera.

Konfiguracje niezależne od pojazdu nie zmieniają się w zależności od producenta OEM ani pojazdu. Konfiguracja pozostaje taka sama we wszystkich pojazdach każdego producenta OEM. Konfiguracje specyficzne dla pojazdu mogą się różnić w zależności od pojazdu i producenta OEM, chociaż konfiguracja może być taka sama dla wszystkich pojazdów wyprodukowanych przez konkretnego producenta OEM.

Konfiguracja APEX

W czasie działania Orchestrator przechodzi do rejestru pakietów usług, aby pobrać orkiestrację SDV dla każdego pakietu usług, wczytując i parsując każdą konfigurację. Więcej informacji znajdziesz w artykule Metadane orkiestracji.

Konfiguracja na maszynę wirtualną

Po uruchomieniu aranżer wczytuje i analizuje konfigurację maszyny wirtualnej (jeśli jest dostępna). Ścieżka bezwzględna do tego pliku konfiguracyjnego jest określana przez właściwości systemu persist.sdv.orchestrator_config_path i ro.boot.sdv.orchestrator_config_path.

Ścieżkę do pliku konfiguracyjnego maszyny wirtualnej system określa podczas rozruchu na podstawie tej hierarchii:

  1. System sprawdza usługę persist.sdv.orchestrator_config_path. Jeśli ma wartość, używana jest ta ścieżka. Ta wartość jest zachowywana po ponownym uruchomieniu lub ustawiana w czasie działania.

  2. Jeśli pole persist.sdv.orchestrator_config_path jest puste, system sprawdza właściwość ro.boot.sdv.orchestrator_config_path. Jeśli właściwość ro.boot.sdv ma wartość, ścieżka jest kopiowana do właściwości persist i używana podczas bieżącego i wszystkich przyszłych uruchomień (chyba że zostanie zastąpiona).

persist.sdv.orchestrator_config_path

persist.sdv.orchestrator_config_path to podstawowa właściwość używana przez agenta SDV Orchestrator do uzyskiwania ścieżki do pliku konfiguracyjnego. Jest to właściwość trwała, co oznacza, że jej wartość jest zapisywana po ponownym uruchomieniu urządzenia. Wartość można zmienić w czasie działania, co jest przydatne w przypadku testowania lub określonych scenariuszy (np. testów kompleksowych).

Wartość możesz ustawić w czasie działania za pomocą polecenia setprop, a w czasie kompilacji za pomocą pliku makefile (z rozszerzeniem .mk) lub pliku skryptu zasobów z rozszerzeniem .rc.

Ustawianie właściwości w czasie działania

Ustawianie właściwości w czasie działania jest przydatne do testowania lub wprowadzania tymczasowych zmian, ponieważ wartość jest zapisywana po ponownym uruchomieniu:

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

Ustawianie właściwości w czasie kompilacji

Aby ustawić tę właściwość w konfiguracji kompilacji urządzenia, dodaj wiersz do pliku makefile produktu lub płyty. Jest to idealne rozwiązanie do ustawiania domyślnej wartości dla nowego obrazu urządzenia.

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

Możesz też ustawić tę właściwość w pliku skryptu zasobu:

# 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 to właściwość tylko do odczytu, która jest używana podczas uruchamiania systemu do podawania początkowej wartości właściwości persist.sdv.orchestrator_config_path. Jeśli persist.sdv.orchestrator_config_path jest pusta podczas uruchamiania systemu, kopiowana jest do niej wartość ro.boot.sdv.orchestrator_config_path. Po ustawieniu wartości parametru persist.sdv.orchestrator_config_path nie zostanie ona zastąpiona przez tę właściwość podczas kolejnych uruchomień.

Wartość ro.boot.sdv.orchestrator_config_path możesz ustawić za pomocą pliku bootconfig lub wiersza poleceń jądra.

Format pliku

Zdefiniuj konfigurację orkiestracji w formacie .textproto (np. w tekście strukturalnym), aby nowe konfiguracje można było wczytywać w czasie działania.

Składnia konfiguracji

W tej sekcji opisujemy składnię konfiguracji.

Pakiety usług

Każdy pakiet usług musi być zdefiniowany za pomocą konfiguracji pakietu usług, która identyfikuje pakiet w Orchestratorze i jest używana do zarządzania cyklem życia instancji pakietu. Konfiguracja pakietu usług określa:

  • InstanceToGroupMapping umożliwia uwzględnienie instancji pakietu usług w grupie w celu ustalenia zależności między instancjami tego samego pakietu usług.

  • InstancesStates określa różne stany pakietu usług.

  • InstancesStateConfiguration określa stan (z InstancesStates), w jakim musi być ustawiona instancja pakietu usług, jeśli warunek ma wartość true.

  • ServiceBundleConfig zawiera informacje o konkretnym pakiecie usług i jego instancjach. Zawiera odpowiednie wartości InstanceToGroupMappingInstancesStateConfiguration dla pakietu.

  • CustomModes określa listę niestandardowych trybów, w których pakiet może publikować treści. CustomModes zapobiega modyfikowaniu wartości trybu niestandardowego przez nieautoryzowany pakiet. To pole jest opcjonalne, ponieważ pakiet usług może nie być publikowany w żadnym trybie niestandardowym. Więcej informacji znajdziesz w sekcji Tryby niestandardowe.

Wymagana konfiguracja pakietu

Konfiguracja pakietu musi zawierać co najmniej te atrybuty:

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

    instance: "instance_1"
    instance: "instance_n"
}

Ta deklaracja definiuje n instancje pakietu usług z odpowiednimi nazwami FQIN:

vm_name.package_name.service_bundle_name.instance_1

vm_name.package_name.service_bundle_name.instance_n

Nazwa maszyny wirtualnej nie jest wyraźnie zadeklarowana w konfiguracji. Ponieważ konfiguracja jest zdefiniowana dla każdej maszyny wirtualnej, nazwa maszyny wirtualnej jest zawsze nazwą maszyny wirtualnej, na której jest wdrażany plik konfiguracyjny, i jest już znana agentowi orkiestracji.

Konfigurowanie instancji

Deklarowanie instancji pakietów usług nie ma wpływu na działanie. Aby instancje mogły być wykonywane przez aranżera, muszą być skonfigurowane. Na przykład Orchestrator musi wiedzieć, w jakich warunkach (lub w jakim stanie maszyny wirtualnej lub pojazdu) powinna działać instancja. Aby skonfigurować instancje, należy zdefiniować stany konfiguracji za pomocą:

  • condition to wyrażenie dotyczące stanu maszyny wirtualnej lub pojazdu, które powinno zostać ocenione.

  • instances_states to zestaw stanów na instancję, które powinny być stosowane, jeśli warunek zwraca wartość true.

Więcej informacji znajdziesz w sekcji Warunki.

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

Mapowanie instancji na grupę

Możesz też skonfigurować instancje usług, dodając je do grup usług. Na poziomie konfiguracji pakietu usług możesz dodawać instancje do grup. Następnie możesz skonfigurować grupy na poziomie konfiguracji maszyny wirtualnej. Więcej informacji znajdziesz w następnej sekcji i w artykule Pakiety usług.

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

Schemat Proto

Oto przykładowy schemat 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;
}

Konfiguracja na poziomie maszyny wirtualnej

Konfiguracja maszyny wirtualnej umożliwia zdefiniowanie mapowań grup i konfiguracji grup. Służy do modelowania zależności między pakietami usług na poziomie maszyny wirtualnej, co zapewnia elastyczność w zakresie jednoczesnego modyfikowania stanu wielu pakietów usług. Wszystkie instancje grupy zostaną przeniesione do określonego stanu.

Orchestrator nie gwarantuje kolejności wykonywania zmiany stanu. Orchestrator promuje każdą instancję do podanego stanu.

Grupy są deklarowane niejawnie przez użycie nazwy group w dowolnej części konfiguracji. Na przykład mapowanie instancji na grupę, mapowanie grupy na grupę i stany konfiguracji grupy.

Mapowanie grupy na grupę

Grupy mogą zawierać inne grupy. Deklarując, że group_1 zawiera subgroup_2, dodajemy wszystkie instancje usługi z subgroup_2 do group_1.

Przykład:

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

Konfigurowanie grupy

Zadeklarowanie grupy nie ma żadnego wpływu. Aby grupy mogły być wykonywane przez aranżera, muszą być skonfigurowane. Na przykład koordynator musi wiedzieć, w jakich warunkach lub w jakim stanie maszyny wirtualnej lub pojazdu mają być uruchamiane grupy.

Grupy możesz konfigurować podobnie jak instancje usług, czyli za pomocą stanów konfiguracji. Jedyna różnica polega na użyciu w składni znaku groups_states zamiast instances_states:

state {
    condition {
        power_state: "ON"
    }

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

Schemat Proto

Oto przykładowy schemat proto:

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

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

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

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

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

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

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

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

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

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

Stany konfiguracji

Stany konfiguracji (states) określają, kiedy instancja usługi lub grupa jest uruchamiana, zatrzymywana lub niszczona. Składają się z conditionsinstances_states (konfiguracja pakietu) oraz groups_states (konfiguracja maszyny wirtualnej).

Warunki

Warunki umożliwiają modelowi zastosowanie warunku logicznego, który po ocenie jako true powoduje zastosowanie zdefiniowanego stanu instancji. Warunek ma te cechy:

  • Dowolnie złożone wyrażenie logiczne (utworzone za pomocą wyrażeń and lub not) oparte na obsługiwanych sygnałach, takich jak zasilanie, pojazd i tryb niestandardowy.

  • (Opcjonalnie) Stan konfiguracji bez warunku jest zawsze aktywny, co oznacza, że przyjmuje wartość true.

Stany instancji i stan grupy

instances_statesgroups_states mają te cechy.

  • Określ, które stany są potrzebne agentowi orkiestracji, aby zastosować je do podanych instancji lub grup, pod warunkiem, że stan jest active

  • Gdy zastosujesz stan do grupy, będzie on dotyczył każdej instancji pakietu usług w tej grupie. Nie ma określonej kolejności, w jakiej instancje są przenoszone do tego stanu.

Obsługiwane stany:

  • started po wywołaniu Service::on_start.

  • created

    • po wywołaniu funkcji Service::new, ale przed wywołaniem funkcji Service::on_start.

      LUB

    • po wywołaniu funkcji Service::on_stop, ale przed wywołaniem funkcji Service::drop.

  • destroyed po wywołaniu Service::drop.

Zbiór reguł

Stan konfiguracji może być aktywny lub nieaktywny w zależności od warunku. W dowolnym momencie może być aktywnych wiele stanów. Gdy agent orkiestracji otrzyma aktualizację sygnału, wszystkie stany konfiguracji są oceniane przed zmodyfikowaniem cyklu życia pakietów usług. Stany instancji usługi są oceniane zgodnie z tymi regułami:

  • Gdy do instancji usługi nie ma zastosowania żaden z aktywnych stanów, jest ona usuwana.

  • Gdy obowiązuje co najmniej jeden z tych stanów, obowiązuje ta kolejność:

    1. destroyed ma bezwzględne pierwszeństwo.
    2. started ma pierwszeństwo przed created.

Schemat Proto

Oto przykładowy schemat proto:

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

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

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

Strategia przywracania po awarii i ponownego uruchamiania

Orchestrator zapewnia niezawodny mechanizm obsługi awarii pakietów usług i błędów przejścia cyklu życia. Orchestrator ma całościowy wgląd w stany usług i zarządza przejściami między trybami, dlatego jest najbardziej odpowiednim komponentem do realizacji strategii ponownego uruchamiania i ponawiania. Menedżer cyklu życia (LM) zgłasza awarie pakietu usług do Orchestratora za pomocą powiadomień o zakończeniu działania usługi. Aby uniknąć niepotrzebnych wywołań interfejsu Binder do LM, koordynator buforuje ostatni stan każdego pakietu (niezależnie od tego, czy operacja się powiodła), i nie stosuje ponownie przejść, jeśli ostatni znany stan jest taki sam jak nowy żądany stan.

Konfiguracja ponawiania

Strategię ponownego uruchamiania i ponawiania możesz zdefiniować dla każdej instancji w konfiguracji Orchestratora za pomocą retry_mapping. Jeśli w konfiguracji nie ustawisz wartości max_retries, domyślna wartość zostanie pobrana z właściwości systemowej ro.boot.sdv.orchestrator.recovery.max_retries. Jeśli ta właściwość nie jest skonfigurowana, domyślnie stosowana jest wartość 0.

  • max_retries: określa liczbę ponownych prób przejścia przez aranżera po tymczasowym niepowodzeniu lub powiadomieniu o awarii pakietu. Licznik ponownych prób resetuje się do wartości max_retries po udanej operacji lub po przetworzeniu nowego trybu. Jeśli kilka mapowań jest kierowanych na tę samą instancję, pierwszeństwo ma mapowanie z najwyższym max_retries.

Przykładowa konfiguracja

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

Zachowanie regeneracji

Logika ponownego uruchamiania i ponawiania działania Orchestratora umożliwia sprawne zarządzanie kilkoma scenariuszami awarii:

  • Awaria podczas normalnego działania: jeśli pakiet usług ulegnie awarii podczas działania, usługa Orchestrator zastosuje strategię ponownego uruchamiania i spróbuje przywrócić pakiet do ostatniego żądanego stanu na podstawie pozostałych prób.
  • Awaria podczas przechodzenia do innego trybu: jeśli pakiet ulegnie awarii podczas wymuszania nowego trybu, żądanie ponownego uruchomienia zostanie umieszczone w kolejce i przetworzone później. Po przetworzeniu żądania Orchestrator sprawdza, jaki był ostatni stan instancji, i ponownie uruchamia ją tylko wtedy, gdy nie jest ona w ostatnim żądanym stanie (z ostatniego przejścia trybu).
  • Nowy tryb podczas przywracania: jeśli Orchestrator otrzyma żądanie przejścia do nowego trybu podczas ponownego uruchamiania pakietu (lub gdy pakiet znajduje się w kolejce instancji do ponownego uruchomienia), anuluje trwające przywracanie. Następuje przejście do nowego trybu, a licznik ponownych prób zostaje zresetowany, aby umożliwić nową serię prób osiągnięcia nowego stanu docelowego.

Orchestrator rozróżnia różne typy błędów zwracanych przez Lifecycle Manager, aby określić strategię ponawiania:

  • Błędy przejściowe (SERVICE_NOT_FOUND, OPERATION_FAILED, INTERNAL_ERROR): koordynator ponawia operację bez podejmowania żadnych specjalnych działań czyszczących.
  • Błędy trwałe (VALUE_CORRUPTED, INVALID_ARGUMENT): koordynator zakłada, że pakiet usług może być uszkodzony, i próbuje zakończyć działanie instancji usługi przed ponowieniem operacji, aby zapewnić czysty restart.
  • Błędy trwałe (PERMISSION_DENIED): operacja nie jest ponawiana, a pakiet jest uznawany za nieodwracalnie uszkodzony.

Jeśli Menedżer cyklu życia ulegnie awarii, wszystkie procesy pakietu usług zostaną utracone. Ponieważ rzeczywisty stan jest nieznany, aranżer unieważnia każdą instancję i stosuje strategię ponownego uruchamiania z pozostałymi próbami, aby przywrócić każdą instancję do ostatniego żądanego stanu.

Aby zapobiec nieskończonym pętlom przywracania w przypadku pakietów, które regularnie ulegają awarii lub nie działają prawidłowo, licznik ponownych prób jest resetowany do wartości max_retries tylko po pomyślnym zakończeniu operacji cyklu życia lub gdy zostanie zgłoszone żądanie przejścia do nowego trybu. Jeśli pakiet wyczerpie liczbę ponownych prób z powodu kolejnych błędów (np. błędu przejścia, po którym nastąpi awaria), nie zostanie ponownie uruchomiony, dopóki licznik ponownych prób nie zostanie zresetowany.

Raportowanie stanu do monitora stanu

Orchestrator udostępnia wewnętrzny interfejs bindera, w którym rejestruje się monitor stanu (HM), co umożliwia mu ciągłe otrzymywanie aktualizacji dotyczących stanu wszystkich pakietów usług. W tym interfejsie aranżer aktywnie raportuje:

  • Stan cyklu życia: zamierzony stan instancji na podstawie bieżącej konfiguracji i aktywnych trybów (np. uruchomiony, utworzony lub zniszczony).
  • Stan odzyskiwania: stan osiągnięcia zamierzonego stanu cyklu życia, wskazujący, czy instancja działa, czy obecnie ponawia próbę po awarii, czy nie udało się jej odzyskać po wyczerpaniu wszystkich prób.

Te informacje są raportowane w przypadku wszystkich instancji, w tym tych, które nie zostały zarejestrowane do monitorowania za pomocą sygnału o stanie. HM używa tych informacji do implementowania interfejsów API, aby raportować stan maszyny wirtualnej. Więcej informacji znajdziesz w sekcji Monitorowanie stanu zdrowia.

Przykłady

W tej sekcji znajdziesz przykłady konfigurowania stanów z warunkami.

Przykładowa usługa podstawowa
  • Nie ma warunku, więc jest zawsze aktywna.
  • Uruchamia pojedynczą instancję usługi.
state {
  # Note: This state has no condition, hence its actions are valid throughout the lifetime of the program
  instances_states { started: "ServiceBundleName" }
}
Przykładowa aplikacja do ogrzewania, wentylacji i klimatyzacji
  • Warunek: aktywny, gdy custom_state != occupancy.OCCUPANCY_EMPTY || custom_state == preheat.PREHEAT_ON.

  • Deklaruje wiele instancji usług związanych z HVAC jako 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"
  }
}
Przykładowe oszczędzanie energii
  • Warunek: aktywny, gdy custom_state == system_power.SYSTEM_POWER_LOW && custom_state == range_ext.RANGE_EXT_ON.

    Ten stan można traktować jako stan oszczędzania energii.

  • Deklaruje jedną instancję usługi związaną z HVAC jako destroyed.

  • W tym przykładzie, gdy aktywne są tryby SYSTEM_POWER_LOWRANGE_EXT_ON, aplikacja HVAC działa bez instancji usługi 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" }
    }
    
Przykładowy film o życiu na pokładzie
  • Warunek: aktywny, jeśli power_state == ON && vehicle_state == LIFE_ON_BOARD.

    Ten stan można interpretować jako ktoś jest w samochodzie i samochód jest włączony.

  • Deklaruje, że czujniki temperatury działają.

  • Gdy ktoś jest w samochodzie, ze względów bezpieczeństwa monitorowane są takie elementy jak temperatura.

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

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

Przykłady

Ta sekcja zawiera pełne przykłady, które obejmują:

  • Konfiguracja protokołu na poziomie pakietu usług, która wprowadza pakiet usług z 2 instancjami, z których każda jest częścią grupy.

  • Konfiguracja protokołu na poziomie maszyny wirtualnej, która wprowadza logikę interakcji z grupami na podstawie trybów

Konfiguracja na poziomie pakietu usług

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

Konfiguracja na poziomie maszyny wirtualnej

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

Konfigurowanie równoległości zarządzania pakietami

Właściwość systemowa ro.boot.sdv.max_bundles_management_threads jest kluczowym parametrem dostrajania, który umożliwia kontrolowanie wydajności i zużycia zasobów podczas operacji związanych z cyklem życia pakietu usług. Określa maksymalny poziom równoległości transakcji pakietów usług i ma bezpośredni wpływ na 2 usługi podstawowe:

  1. Silnik orkiestracji: ta usługa odczytuje właściwość, aby określić, ile jednoczesnych wywołań (np. startService, stopService) może wykonać orkiestrator w usłudze Lifecycle Manager. Jest to kluczowe dla wydajności podczas uruchamiania i przełączania trybów, gdy wiele pakietów może jednocześnie zmieniać stan.

  2. Menedżer cyklu życia: ta usługa używa wartości właściwości do obliczania rozmiaru puli wątków Binder, która odpowiada za obsługę wszystkich przychodzących żądań. Dzięki temu model językowy będzie miał wystarczającą liczbę wątków do obsługi jednoczesnych żądań z aranżera.

Jeśli ta właściwość nie jest skonfigurowana, obie usługi domyślnie przyjmują wartość 12.

Metoda konfiguracji

Możesz ustawić właściwość w pliku BoardConfig.mk na urządzeniu, dodając ją do zmiennej BOARD_BOOTCONFIG. Dzięki temu wartość jest stosowana za każdym razem, gdy urządzenie się uruchamia.

BOARD_BOOTCONFIG += \
    androidboot.sdv.max_bundles_management_threads=8

Aby zmienić wartość na urządzeniu, zmodyfikuj ten wiersz w odpowiednim pliku BoardConfig.mk i ponownie skompiluj aplikację.

Optymalizacja czasu uruchamiania

ro.sdv.orchestrator.state.ready to write-once właściwość logiczna, która jest częścią strategii optymalizacji wydajności podczas uruchamiania. Oznacza to, że agent orkiestracji zakończył inicjowanie i jest gotowy do rozpoczęcia zarządzania cyklem życia pakietów usług. Jego głównym celem jest nadawanie priorytetu uruchamianiu Orchestratora i jego pakietów usług zarządzanych przez kontrolowanie sekwencji uruchamiania innych agentów SDV.

  • Ustawione przez: agenta orkiestracji.
  • Kiedy: raz podczas sekwencji uruchamiania.
  • Użycie: ta właściwość jest używana przez system inicjujący do kontrolowania sekwencji uruchamiania większości agentów SDV (Menedżer aktualizacji, dostawca VSIDL, Monitor stanu, Odkrywanie usług, Tunel danych, RPC, VPM i Telemetria). Wcześniejsze uruchomienie aranżera i oczekiwanie innych agentów na tę właściwość sprawia, że aranżer może rozpocząć krytyczne zadanie uruchamiania pakietów usług bez konkurowania o zasoby systemowe.

Wydajność

Podczas uruchamiania systemu jednoczesne uruchamianie wszystkich agentów może prowadzić do rywalizacji o zasoby, co spowalnia cały proces uruchamiania. Aby temu zapobiec, wymuszamy sekwencyjną kolejność uruchamiania za pomocą właściwości systemu:

  1. Rejestr pakietów usług: wczytuje się jako pierwszy, aby załadować wszystkie metadane pakietu usług.
  2. Menedżer cyklu życia i Orchestrator: te podstawowe agenty uruchamiają się, gdy tylko rejestr jest gotowy. Wczesne rozpoczęcie jest kluczowe, ponieważ umożliwia Orchestratorowi rozpoczęcie oceny konfiguracji i przygotowanie do natychmiastowego uruchomienia pakietów usług.
  3. Inne agenty SDV: uruchamiają się dopiero po przygotowaniu aranżera.

Ta kontrolowana sekwencja zapewnia, że Orchestrator ma priorytet w zakresie korzystania z zasobów systemowych, aby jak najszybciej uruchamiać pakiety usług, co prowadzi do szybszego, bardziej deterministycznego i wydajniejszego uruchamiania systemu.

Tryby wykorzystywane przez aranżera

Agent orkiestracji utrzymuje aktywną subskrypcję trybów pojazdu i zasilania przesyłanych przez VPM. Po nawiązaniu początkowego połączenia między Orchestratorem a systemem zarządzania pojazdem i zasilaniem (VPM) Orchestrator ustawia te właściwości systemowe typu boolean na true:

  • sdv.orchestrator.bootup.power_mode.ready

  • sdv.orchestrator.bootup.vehicle_mode.ready

Na podstawie pliku konfiguracyjnego agent orkiestracji dynamicznie oblicza zestaw pakietów usług, które powinny być uruchomione, na podstawie bieżących wartości otrzymanych trybów. Orchestrator komunikuje się następnie z menedżerem cyklu życia, wydając różne polecenia, aby dostosować rzeczywisty stan pakietów usług do obliczonego stanu docelowego.

Stan pojazdu i zasilania

Agent trybu pojazdu i zarządzania energią (VPM) umożliwia komponentom SDV uzyskiwanie informacji o bieżącym stanie pojazdu, np. o trybie pracy (np. parkowanie lub jazda) i stanie zasilania (np. włączony lub zawieszony). Orchestrator ocenia te wartości, aby określić, które pakiety usług powinny być uruchamiane na podstawie konfiguracji Orchestratora. Więcej informacji znajdziesz w artykule Zarządzanie pojazdem i zasilaniem.

Tryby niestandardowe

Ze względu na ich liczbę nie możemy modelować wszystkich trybów pojazdów. Każdy producent OEM ma inne potrzeby, a standaryzacja trybów pojazdów nie może uwzględniać wszystkich przypadków użycia. Dlatego obsługujemy tryby specyficzne dla OEM, zwane trybami niestandardowymi. Te tryby nie rozszerzają istniejących trybów pojazdu i zasilania. Zamiast tego umożliwiają one definiowanie nowych trybów.

Funkcjonalność:

  • Zakres globalny: tryby niestandardowe mają charakter globalny i są stosowane jednolicie na wszystkich maszynach wirtualnych zarządzanych przez Orchestratora.

  • Kompozycja: każda zmiana trybu niestandardowego składa się z 2 elementów:

    • Nazwa: unikalny identyfikator wybrany przez producenta OEM do reprezentowania trybu niestandardowego.

    • Wartość: bieżący stan trybu niestandardowego, który może mieć wartość UNDEFINED, gdy nie jest ustawiona żadna wartość.

  • Rola koordynatora: koordynator działa jako pasywny odbiorca wartości trybu niestandardowego.

  • Rola pakietu usług: każdy pakiet usług może mieć wiele trybów niestandardowych i publikować nowe wartości w dowolnym z nich. Ten sam tryb niestandardowy może należeć do wielu pakietów usług, co oznacza, że może on otrzymywać nowe wartości z różnych źródeł.

  • Odpowiedzialność za weryfikację: producenci OEM odpowiadają za zapewnienie prawidłowych przejść między stanami. Orchestrator akceptuje każdą nową wartość.

Szacowane cechy:

  • Szacunkowa liczba: tryby zasilania i pojazdu zarządzają cyklem życia większości pakietów usług, a tryby niestandardowe odgrywają rolę uzupełniającą. Spodziewamy się, że liczba trybów niestandardowych będzie wynosić kilkadziesiąt, a nie kilkaset.

  • Szacowane ramy czasowe: tryby nie są wysyłane okresowo. Zamiast tego tryby są oparte na zdarzeniach i uruchamiane przez określone działania, takie jak otwarcie drzwi, rozpoczęcie sekwencji parkowania, rozpoczęcie cyklu ładowania i inne podobne zdarzenia o znaczeniu określonym przez producenta OEM.

Tryb niestandardowy umożliwia definiowanie i zarządzanie konkretnymi trybami, a jednocześnie pozwala orkiestratorowi zachować niezależność od podstawowej logiki automatu stanów.

Obsługiwane tryby

Aby mieć pewność, że pakiety usług są publikowane tylko w należących do nich trybach niestandardowych, każdy z nich musi wyraźnie zadeklarować listę należących do niego trybów niestandardowych w konfiguracji Orchestratora, która jest dostępna na lokalnej maszynie wirtualnej z rejestrem pakietu usług. Próby publikowania w niezadeklarowanym trybie niestandardowym są odrzucane.

Aby zadeklarować tryby niestandardowe, które pakiet usług może publikować (a tym samym posiadać), schemat protokołu service_bundle_config jest rozszerzany o te elementy:

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

Konfigurowanie pakietów na podstawie trybów

Obecna konfiguracja protokołu Orchestrator (komponent Condition) umożliwia manipulowanie pakietami usług na podstawie trybów niestandardowych:

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

Przykładowy plik proto

Poniższy przykład pokazuje, jak skonfigurować instancje pakietu usług, aby były uruchamiane na podstawie stanu TURNFOG:

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

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

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

}

Ustawianie nowych trybów niestandardowych

Proces ustawiania nowej wartości trybu niestandardowego rozpoczyna się od pakietu usług, który przekazuje żądaną wartość do lokalnego narzędzia Orchestrator działającego na tej samej maszynie wirtualnej. Orchestrator sprawdza następnie, czy pakiet usług ma uprawnienia wymagane do publikowania w określonym trybie niestandardowym, odwołując się do konfiguracji zdefiniowanej w .textproto, aby określić, czy powinien propagować wartość na inne maszyny wirtualne. Po rozpowszechnieniu każda usługa Orchestrator sprawdza swoją konfigurację, aby znaleźć listę pakietów usług, w przypadku których należy zmienić stan.

RPC

Każdy Orchestrator działający na każdej maszynie wirtualnej tworzy serwer RPC, który nasłuchuje nowych wartości trybu niestandardowego. Każdy pakiet usług, który chce zaktualizować tryb niestandardowy, musi utworzyć klienta RPC na serwerze. Listy ACL są egzekwowane, aby zapobiec łączeniu się z serwerem nieautoryzowanych pakietów.

Definicja protokołu do ustawiania nowej wartości za pomocą RPC wygląda tak:

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

Anulowanie przejść między stanami zasilania

Aranżer umożliwia anulowanie trwających zmian zasilania za pomocą SHUTDOWN_CANCELLED trybu zasilania (wysyłanego przez VPM do aranżera).

Rozważmy na przykład taką konfigurację Orchestratora:

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

Gdy zostanie odebrany tryb SHUTDOWN_CANCELLED, zachowanie koordynatora zależy od 2 głównych scenariuszy. W obu przypadkach tryb zasilania SHUTDOWN_CANCELLED jest dodawany na końcu kolejki. Następnie po wykorzystaniu elementów w kolejce wykonywana jest funkcja SHUTDOWN_CANCELLED.

Scenariusz 1. Bieżący tryb w trakcie to tryb zasilania

Jeśli aranżer wykonuje aktualizację trybu zasilania, żądane jest anulowanie trwającego trybu. Menedżer cyklu życia nie obsługuje anulowania trwającego procesu przejścia, ale aranżer sprawdza, czy nie są inicjowane żadne nowe żądania pakietu usług.

Przykład: jeśli instance-1 z konfiguracji w poprzednim przykładzie jest w trakcie uruchamiania, gdy zostanie odebrany tryb SHUTDOWN_CANCELLED, instance-1 dokończy uruchamianie. Jednak instance-2instance-3 nie przechodzą do stanu rozpoczętego.

Scenariusz 2. W kolejce przetwarzania jest tryb zasilania

Jeśli koordynator przetwarza aktualizację trybu innego niż tryb zasilania, a w kolejce trybów do wykonania znajduje się żądanie zasilania, przejście zasilania jest usuwane z kolejki. Zapobiega to jego wykonaniu.

Przykład: jeśli w konfiguracji z poprzedniego przykładu koordynator przetwarza aktualizację niezwiązaną z zasilaniem (np. aktualizację pojazdu), a w kolejce znajduje się zadanie SUSPEND_TO_RAM_ENTER, otrzymanie zadania SHUTDOWN_CANCELLED spowoduje, że żadna z instancji (instance-1, instance-2, instance-3) nie zostanie uruchomiona.

Przykładowa implementacja

Katalog klienta, który chce używać kodu wygenerowanego przez oprogramowanie pośredniczące do utworzenia klienta serwera RPC, może wyglądać tak jak w tym przykładzie:

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

Podczas generowania kodu musisz dodać zależność do katalogu Orchestratora:

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

Kod klienta do wysyłania nowej wartości wygląda tak:

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

Narzędzia do debugowania

Agent Orchestrator obsługuje narzędzie dumpsys. Możesz go wywołać, uruchamiając to polecenie na działającej instancji SDV:

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

Użyj tego narzędzia, aby debugować agenta Orchestratora i uzyskać wgląd w jego stan wewnętrzny. Spowoduje to wyświetlenie:

  • Obecny stan trybów: sprawdź aktywne tryby pojazdu, zasilania i niestandardowe.
  • Wydawcy w trybie niestandardowym: określ, które usługi mogą publikować tryby niestandardowe (i w których trybach).
  • Wymagany stan poszczególnych usług: poznaj stan każdego pakietu usług na podstawie predefiniowanych warunków i bieżących trybów. Pomaga to zdiagnozować, dlaczego usługa może nie być w oczekiwanym stanie.
  • Stan egzekwowania trybu: uzyskaj jasny obraz egzekwowanego trybu w trakcie procesu lub ostatniego egzekwowanego trybu, jeśli żaden nie jest w trakcie procesu.
  • Kolejka egzekwowania trybu: wyświetl tryby oczekujące na egzekwowanie.

Przykład:

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

Aby dowiedzieć się więcej o poszczególnych pakietach usług zarządzanych przez Orchestrator, użyj istniejącego polecenia dumpsys z Menedżera cyklu życia w ten sposób:

dumpsys google.sdv.lifecycle.ILifecycleManager/default

W ten sposób uzyskasz szczegółowe informacje o stanie cyklu życia każdej usługi. Połączenie danych wyjściowych polecenia dumpsys Orchestratora z danymi wyjściowymi Menedżera cyklu życia zapewnia pełny obraz cyklu życia pakietów usług na maszynie wirtualnej.