SDV su QNX

Testiamo internamente SDV sull'hardware. Utilizziamo QVM su QNX per la virtualizzazione. Condividiamo tutti i target, la documentazione e le configurazioni come esempi.

Prerequisiti

Questa pagina presuppone che QNX sia preconfigurato e non include i passaggi per creare, configurare o eseguire il flashing di QNX sull'hardware.

Questa pagina presuppone che tu stia eseguendo QNX su hardware arm64 e che stia creando e utilizzando i target _arm64 di SDV.

Componenti richiesti

  • Un blob Device Tree (DTB) per definire l'hardware virtuale
  • Un kernel Linux da utilizzare
  • Un ramdisk combinato che include tutte le proprietà di avvio del ramdisk
  • Un passaggio di una catena DICE per l'autenticazione della VM SDV
  • Tutte le partizioni del disco del sistema
  • Una configurazione QVM della VM

Blob Device Tree (DTB)

QVM genera la maggior parte del blob Device Tree (DTB) in base alla sua configurazione. Pertanto, il DTB può essere minimo:

/*
 * Copyright (C) 2026 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/dts-v1/;

/ {
    model = "Virtual Machine";
    #address-cells = <2>;
    #size-cells = <2>;

    // This reserved-memory node specifies for the open-dice driver which memory region(s) to
    // expose as /dev/open-dice<n> device(s)
    reserved-memory {
        // The number of u32 cells to represent the address of a memory region
        #address-cells = <2>;
        // The number of u32 cells to represent the size of a memory region
        #size-cells = <2>;
        ranges;
        // The unit address (after the @) must match the address in the reg property
        dice@D1C30000 {
            // The open-dice driver receives this device tree node based on this
            // property.
            compatible = "google,open-dice";
            no-map;
            // The address and the size of the memory region that is passed to the
            // open-dice driver.
            // First two hex numbers (cells) represent the address of the memory region,
            // the last two represent its size (4K, in this case).
            reg = <0x0 0xD1C30000 0x0 0x1000>;
        };
    };
};

Kernel

SDV utilizza l'immagine del kernel generico (GKI) e puoi utilizzare direttamente l'output di una build.

Ramdisk

Le informazioni sul ramdisk devono includere i diversi ramdisk generati da Android e le proprietà di avvio. Poiché QNX non supporta un bootloader per impostazione predefinita, devi generare un ramdisk con il formato di dati previsto.

Puoi farlo con il seguente script Python, che concatena più ramdisk e aggiunge il bootconfig (ovvero il file vendor-bootconfig.img) nel formato previsto:

def create_qnx_ramdisk(output: io.BytesIO,
                       ramdisks: Sequence[io.BytesIO],
                       bootconfig: Optional[io.BytesIO]):
  BUFFER_SIZE = 4096

  for ramdisk in ramdisks:
    while buf := ramdisk.read(BUFFER_SIZE):
      output.write(buf)

  # Kernel looks for bootconfig at the end of ramdisk.

  if bootconfig:
    bootconfig_checksum = 0
    bootconfig_size = 0
    while buf := bootconfig.read(BUFFER_SIZE):
      bootconfig_checksum = (bootconfig_checksum + sum(buf)) & 0xFFFFFFFF
      bootconfig_size += len(buf)
      output.write(buf)

    output.write(struct.pack('II', bootconfig_size, bootconfig_checksum))
    output.write(b'#BOOTCONFIG\n')

Catena DICE

In un sistema di produzione, il sistema host e il bootloader costruiscono dinamicamente la catena DICE durante il processo di avvio e forniscono una catena DICE al guest per verificare che l'immagine sia attendibile. Poiché questo requisito può complicare i flussi di test e sviluppo, carichi uno snapshot della catena DICE.

Per generare i file dice_handover_instance*, utilizza qualsiasi build Cuttlefish SDV. Ad esempio:

lunch sdv_core_cf-trunk_staging-userdebug
m
cp $OUT/product/etc/dice_handover_instance* <GUEST>/test_dice_handover

Disco

QVM supporta più formati per un disco virtuale; la nostra configurazione di riferimento utilizza un file immagine del disco che contiene tutte le partizioni. bpttool può generare questi dischi, ma non è sviluppato attivamente in Android.

Configurazione QVM

La configurazione QVM imposta la configurazione e rimanda ai diversi file. Forniamo le seguenti configurazioni di esempio:

Domande frequenti

D: adb non riesce a connettersi alla mia VM. Che cosa posso fare?

R: in questa configurazione, adb utilizza Ethernet per connettersi alla VM. È necessaria una configurazione di port forwarding su QNX che inoltri le richieste ai guest sulla porta 5555. Devi connetterti al sistema host. In alternativa, puoi anche configurare un bridge alla VM e connetterti direttamente.

D: il log di sistema mostra che IServiceRegistrationAgent è mancante. Perché?

La Service Discovery si basa su una configurazione di trust e binder completamente funzionante. Verifica che OpenDICE sia stato caricato correttamente e che HwBinder non mostri errori durante l'avvio. Se non funzionano, devi prima correggerli.

D: init_open_dice non riesce. Che cosa è successo?

R: gli script di avvio caricano le informazioni di trust durante l'avvio e cancellano la posizione di memoria. Verifica nella configurazione QVM che la configurazione della riga di comando e i dati condivisi nella posizione di memoria siano compatibili. Verifica inoltre che la posizione di memoria nel driver, nella configurazione QVM e nel DTB corrisponda e che la posizione di memoria sia scrivibile.