Planung der Dienstqualität in SDV

Das SDV-QoS-Scheduling-Framework (Service Quality of Service) bietet eine deterministische Zuweisung von CPU-Ressourcen für Service-Bundles, die vom Lifecycle Manager (LM) verwaltet werden. Durch die Abstraktion von Linux-Scheduling-Attributen auf niedriger Ebene (Policy, Priority, Nice) in logische Voreinstellungen ermöglicht die Plattform eine saubere Trennung zwischen der Entwicklung von Diensten und der systemweiten Abstimmung des Fahrzeugs. So wird die erforderliche Rechenbandbreite für sicherheitskritische und zeitkritische Arbeitslasten bereitgestellt, während das System Hintergrundaufgaben einschränkt, um Instabilität zu vermeiden.

Rollen und Verantwortlichkeiten

Das SDV-Planungsmodell folgt einem Muster mit delegierter Verantwortung, um sicherzustellen, dass die Dienste portierbar bleiben, während der OEM das System abstimmen kann.

Rolle Verantwortung Wichtigstes Ergebnis
SDV-Plattform (Google) Definiert das sdv_service_bundles_scheduling.proto-Schema, implementiert die LM-Durchsetzungslogik und stellt die sdv_service_bundles_scheduling-Clientbibliothek bereit. Protobuf-Definitionen und Plattformbibliotheken
OEM (Systemintegrator) Definiert die konkreten Werte für jede Voreinstellung, z. B. was ELEVATED auf bestimmter Hardware bedeutet, und steuert die systemweite Konfiguration. /product/etc/lifecycle_config.textproto
Dienstentwickler Wählt den entsprechenden logischen Voreinstellungsnamen aus und registriert den scheduling_config.textproto-Pfad im Dienstbundle-Manifest. scheduling_config.textproto und sdv_service_bundles_manifest.textproto

Technischer Workflow

  1. Plattformintegration:Der OEM definiert die fahrzeugspezifische lifecycle_config.textproto. In dieser Datei werden die systemweiten Scheduling-Profile (Voreinstellungen) festgelegt und anhand der Zielhardware konkreten Linux-Scheduling-Attributen zugeordnet.
  2. Entwicklung von Service-Bundles:Der Entwickler bündelt ein scheduling_config.textproto in seinem APEX-Paket, empfiehlt eine logische Voreinstellung (z. B. ELEVATED) und definiert alle internen Thread-Namen.
  3. Integration von Service-Bundles:Während der Fahrzeugintegrationsphase überprüft der OEM die vom Entwickler empfohlene Voreinstellung. Der OEM kann das empfohlene Profil beibehalten oder überschreiben, z. B. einen ELEVATED-Dienst auf NORMAL herabstufen, um die allgemeine Systemstabilität zu verbessern, bevor er das APEX signiert.
  4. Auflösung von Laufzeitattributen:Wenn ein Dienst gestartet wird, identifiziert der LM das autorisierte Preset aus dem Manifest des Dienstes und ruft die entsprechenden Linux-Attribute aus der Systemkonfiguration des OEM ab.
  5. Synchronisierung und Erzwingung beim Start:Der LM wendet die aufgelösten Attribute auf den Dienstprozess an, bevor er ihn mit dem Signal-and-Continue-Protokoll zur Fortsetzung der Ausführung signalisiert.

Wichtige Konzepte

Die folgenden Konzepte sind für das SDV-Planungsframework von zentraler Bedeutung.

Voreinstellungen für die Planung

Planungsvoreinstellungen sind der primäre Mechanismus zur Verwaltung der Dienstqualität in SDV. Anstatt rohe Linux-Planungsparameter zu definieren, verweisen Entwickler auf vordefinierte Voreinstellungen. Zur Laufzeit ordnet der LM diese logischen Namen konkreten Linux-Planungsattributen zu.

Die folgenden Voreinstellungen sind als Beispiel in lifecycle_config.textproto konfiguriert:

Name der Voreinstellung Planungsrichtlinie Typischer Nice-Wert Typisches Anwendungsbeispiel
NORMAL SCHED_OTHER 0 Standarddienste (HLK, Medien, Einstellungen)
ELEVATED SCHED_OTHER -10 Kernsystemkomponenten und Infrastruktur
IDLE SCHED_IDLE 19 Hintergrundanalysen und nicht kritische Protokollierung
CUSTOM Benutzerdefiniert -20 (initial) Dienste, für die Echtzeitrichtlinien oder Affinität erforderlich sind

Wenn ein Preset angewendet wird, verwendet der LM den Systemaufruf setpriority, um den prozessweiten Wert nice festzulegen. Dies wirkt sich auf den relativen CPU-Anteil aus, den der Prozess bei Konflikten unter dem standardmäßigen Linux Completely Fair Scheduler (CFS) erhält.

Berechtigung und Sicherheit

Um eine unbefugte Prioritätserhöhung zu verhindern, verwendet die SDV-Plattform ein mehrstufiges Sicherheitsmodell, das auf SELinux-Domains und Linux-Funktionen basiert.

Sicherheitsbereiche

  • untrusted_service_bundle: Die Standarddomain für Standardvoreinstellungen (NORMAL, ELEVATED, IDLE). Der Kernel schränkt Prozesse in dieser Domain ein und verhindert, dass sie ihre eigenen Scheduling-Parameter ändern.
  • priority_service_bundle: Wird jedem Dienstbündel mit einer Voreinstellung gewährt, bei der is_privileged: true in der systemweiten lifecycle_config.textproto festgelegt ist. Durch die Umstellung auf diese Domain erhält der Prozess die CAP_SYS_NICE-Funktion und kann seine eigene Ressourcenzuweisung verwalten.

CAP_SYS_NICE-Funktion

Die Plattform gewährt Prozessen in der Domain priority_service_bundle die Funktion CAP_SYS_NICE. Mit dieser Berechtigung kann ein Prozess Folgendes tun:

  • Den eigenen nice-Wert über die ursprüngliche Zuweisung hinaus erhöhen.
  • Ändern Sie die Planungsrichtlinie in Echtzeitkurse wie SCHED_FIFO oder SCHED_RR.
  • CPU-Affinität mit sched_setaffinity festlegen
  • Konfigurieren Sie spezielle Fristparameter für SCHED_DEADLINE.

Wenn diese Funktion auf eine bestimmte Domain beschränkt wird, wird das systemweite Scheduling-Gleichgewicht geschützt, da Unterbrechungen auf explizit autorisierte Dienste beschränkt werden.

Konfigurationsanleitung

Dieser Abschnitt enthält Konfigurationsanleitungen für OEMs und Dienstentwickler.

OEM-Leitfaden: Systemweite Voreinstellungen

Der OEM definiert Zeitplanungsprofile in /product/etc/lifecycle_config.textproto. Die Plattform bietet ein Beispiel unter lifecycle_management/config/lifecycle_config.textproto, das OEMs an die Fahrzeughardware anpassen müssen.

Beispiel: Echtzeitvoreinstellung definieren

Ein OEM kann ein CRITICAL-Preset für sicherheitsrelevante Dienste definieren, die niemals von Standardanwendungen unterbrochen werden dürfen:

# lifecycle_config.textproto
scheduling_presets {
  name: "CRITICAL"
  is_privileged: true
  thread_scheduling_configuration {
    policy: 1      # SCHED_FIFO
    priority: 80   # High real-time priority
  }
}

Entwicklerleitfaden: Dienstpaketkonfiguration

Dienstentwickler empfehlen eine Voreinstellung und definieren optional logische Thread-Namen in einer scheduling_config.textproto-Datei. Damit die Plattform diese Datei finden kann, muss der Pfad zu dieser Datei in sdv_service_bundles_manifest.textproto registriert sein.

Beispiel: Manifestregistrierung

# sdv_service_bundles_manifest.textproto
service_bundle_entries {
  name: "SensorService"
  scheduling_config_path: "configs/scheduling_config.textproto"
}

Beispiel: Standardvoreinstellung verwenden

Bei den meisten Diensten reicht es aus, im scheduling_config.textproto auf einen Voreinstellungsnamen zu verweisen:

# configs/scheduling_config.textproto
scheduling_preset_name: "ELEVATED"

Beispiel: Planung für von Diensten erstellte Worker-Threads

Ein Dienstentwickler kann in seinem Code zusätzliche Worker-Threads erstellen, um spezielle Aufgaben wie einen Sensor-Datenloop mit geringer Latenz zu verarbeiten. Der Entwickler kann benannte Planungsattribute für diese internen Threads in der Konfigurationsdatei definieren.

Verwenden Sie die manuelle Anwendung nur in privilegierten Diensten, die diese Metadaten verwenden, um Eigenschaften für ihre internen Worker-Threads festzulegen:

# configs/scheduling_config.textproto
scheduling_preset_name: "CUSTOM"

# Map of logical thread names to their attributes (propagated as metadata)
thread_scheduling_configuration {
  key: "sensor-processing-thread"
  value {
    policy: 1        # SCHED_FIFO
    priority: 50
    cpu_affinity_ids: [2, 3]  # Pin to specific cores
  }
}

Systemverhalten und Durchsetzung

Die SDV-Plattform verwendet ein strenges Durchsetzungsmodell, um Planungskonfigurationen zu aktivieren, bevor dienstspezifischer Code ausgeführt wird.

Synchronisierung beim Start

Damit ein Dienst nicht mit einer falschen Priorität ausgeführt wird (auch nicht während der Initialisierungsphase), verwenden der LM und der Service Bundle Runner (SBR) ein Signal-and-Continue-Synchronisierungsprotokoll:

  1. Prozesserstellung:Der LM forkt den SBR-Prozess. An diesem Punkt wird der untergeordnete SBR-Prozess ausgeführt, geht aber sofort in einen blockierten Zustand über und wartet auf ein Signal auf seinem stdin.
  2. Attributanwendung:Während das untergeordnete Element blockiert ist, wendet der LM den angeforderten nice-Wert mit dem Systemaufruf setpriority an und konfiguriert die Planungsrichtlinie (z. B. SCHED_IDLE).
  3. Sicherheitsübergang:Der LM führt den SELinux-Domainübergang durch und verschiebt das untergeordnete Element entweder in die Domain untrusted_service_bundle oder priority_service_bundle.
  4. Signal:Erst wenn alle Parameter erfolgreich angewendet wurden, sendet der LM ein Ein-Byte-Signal an das stdin des untergeordneten Geräts.
  5. Ausführung:Der SBR empfängt das Signal und beginnt mit dem Laden der Dienstbibliotheken und dem Aufrufen von Lifecycle-Methoden.

Auswirkungen auf den Hauptthread und den Lebenszyklus

Durch die Synchronisierung vor dem Laden der Dienstbibliotheken behält die Plattform die angeforderte Priorität für den Hauptausführungsthread über alle Lebenszyklus-Callbacks hinweg bei:

  • onCreate: Alle Abhängigkeitsinjektionen und die anfängliche Ressourcenzuweisung erfolgen mit der richtigen Priorität.
  • onStart: Die Voreinstellung steuert den Übergang in den aktiven Status und alle anfänglichen Arbeitsläufe.
  • onStop und onDestroy: Die Plattform führt Bereinigungsvorgänge mit derselben Priorität aus, um zu verhindern, dass kritische Systemaktivitäten während des Herunterfahrens nicht ausgeführt werden.

Binder-Threadpool und Prioritätsvererbung

Threads im plattformverwalteten Binder-Threadpool führen keine Aufgaben mit der Priorität des Threads aus, der den Pool erstellt hat. Stattdessen erbt der Server-Thread bei synchronen Transaktionen die Priorität des Aufrufers. Der Binder-Kernel-Treiber steuert diesen Mechanismus zur Prioritätsvererbung.

Feinabstimmung auf Thread-Ebene

Bei Service-Bundles, die eine detaillierte Steuerung erfordern (z. B. Echtzeit-Verarbeitungsschleifen), müssen Konfigurationen manuell auf die Worker-Threads angewendet werden. So wenden Sie Konfigurationen auf Thread-Ebene an:

  1. Fordern Sie eine privilegierte Voreinstellung an (wenn is_privileged: true festgelegt ist).
  2. Verwenden Sie die Funktion get_scheduling_configuration aus der Bibliothek sdv_service_bundles_scheduling, um thread_scheduling_configuration zu lesen.
  3. Mit sched_setattr können Sie Worker-Threads Attribute zuweisen.

SELinux und Erzwingen von Berechtigungen

Die Plattform verwendet SELinux und die Linux-Funktion CAP_SYS_NICE, um Zeitplanvorgaben zu erzwingen:

  • Bei Diensten, die Voreinstellungen wie NORMAL oder IDLE verwenden, wird die Planung vom LM beim Start konfiguriert. Diese Dienste haben keine CAP_SYS_NICE-Funktion und ihre Priorität oder Richtlinie kann nicht geändert werden.
  • Diensten, die eine privilegierte Voreinstellung (is_privileged: true) verwenden, wird die Funktion CAP_SYS_NICE gewährt. So können sie die Planung für ihre internen Threads manuell steuern, was für Echtzeitaufgaben erforderlich ist.

Bestätigung und Beispiele

Um das Planungsverhalten zu überprüfen, sind eine Kombination aus Loganalyse und Leistungsmessung auf Systemebene erforderlich. Die SDV-Plattform bietet ein spezielles Beispiel, um diese Techniken zu demonstrieren.

Beispiel für die QoS-Planung

Dieses Beispiel befindet sich in samples/qos_scheduling und enthält mehrere Dienste für Leistungstests, die parallel ausgeführt werden und ihren Fortschritt melden.

  • PerformanceTesterNormal: Wird mit der Voreinstellung NORMAL ausgeführt.
  • PerformanceTesterElevated: Wird mit der Voreinstellung ELEVATED ausgeführt.
  • PerformanceTesterRealtime: Verwendet die Voreinstellung CUSTOM, um SCHED_FIFO auf die internen Worker-Threads anzuwenden.
  • PolicyOffender: Ein Diagnosedienst, der versucht, eine Echtzeitpriorität festzulegen, während eine NORMAL-Voreinstellung verwendet wird. Damit wird überprüft, ob die Plattform unautorisierte Eskalierungen erfolgreich blockiert.

Bestätigungssuite ausführen

  1. Aktivieren Sie die QoS-spezifische Orchestrierungskonfiguration:

    adb shell setprop persist.sdv.orchestrator_config_path /etc/orch/vm_qos_scheduling_orch_config.textproto

  2. Starten Sie das Gerät neu, um die Dienste in den jeweiligen Planungsbereichen zu starten:

    adb reboot

  3. Filtern Sie die Logs, um die Ergebnisse der vergleichenden Leistung zu sehen:

    adb logcat | grep sdv_sample_qos_common

    Der Dienst PerformanceTesterElevated meldet deutlich mehr abgeschlossene Arbeitseinheiten als PerformanceTesterNormal. Die EPERM- oder SELinux-Verweigerungsfehler sind in den Logs für den PolicyOffender-Dienst enthalten.

Abwärtskompatibilität

  • Zur Abwärtskompatibilität wird jedes Legacy-Dienstbündel, in dessen Manifest ein scheduling_config_path angegeben ist, in der Konfigurationsdatei aber kein scheduling_preset_name, automatisch als privilegierter Dienst behandelt. Dadurch bleiben die erforderlichen Berechtigungen (z. B. CAP_SYS_NICE) für ältere Dienste erhalten, die auf der manuellen Thread-Optimierung basieren.
  • Die Root-Konfigurationsnachricht DeadlineSchedulingConfiguration soll in einer zukünftigen Version umbenannt werden. Der aktuelle Name ist historisch und spiegelt nicht mehr genau wider, dass die Nachricht alle Arten der Terminplanung abdeckt, nicht nur die Terminplanung für Fristen.