Wdrażanie wirtualnego A/B

Aby zaimplementować wirtualną A/B na nowym urządzeniu lub zmodernizować uruchomione urządzenie, musisz wprowadzić zmiany w kodzie urządzenia.

Buduj flagi

Urządzenia korzystające z wirtualnego A/B muszą być skonfigurowane jako urządzenia A/B i muszą być uruchamiane z partycjami dynamicznymi .

W przypadku urządzeń uruchamianych z wirtualnym A/B ustaw je tak, aby dziedziczyły podstawową konfigurację wirtualnego urządzenia A/B:

$(call inherit-product, \
    $(SRC_TARGET_DIR)/product/virtual_ab_ota.mk)

Urządzenia uruchamiane z wirtualnym A/B potrzebują tylko o połowę mniejszego rozmiaru płyty dla BOARD_SUPER_PARTITION_SIZE , ponieważ sloty B nie są już w super. Oznacza to, BOARD_SUPER_PARTITION_SIZE musi być większa lub równa sum(rozmiar grup aktualizacji) + narzut , który z kolei musi być większy lub równy sum(rozmiar partycji) + narzut .

Aby włączyć skompresowane migawki z Virtual A/B, odziedzicz następującą konfigurację podstawową:

$(call inherit-product, \
    $(SRC_TARGET_DIR)/product/virtual_ab_ota/compression.mk)

Kontrola rozruchu HAL

HAL kontroli rozruchu zapewnia interfejs dla klientów OTA do kontrolowania gniazd rozruchowych. Virtual A/B wymaga uaktualnienia mniejszej wersji warstwy HAL kontroli rozruchu, ponieważ potrzebne są dodatkowe interfejsy API, aby zapewnić ochronę bootloadera podczas flashowania/przywracania ustawień fabrycznych. Zobacz IBootControl.hal i types.hal , aby uzyskać najnowszą wersję definicji warstwy HAL.

// hardware/interfaces/boot/1.1/types.hal
enum MergeStatus : uint8_t {
    NONE, UNKNOWN, SNAPSHOTTED, MERGING, CANCELLED };

// hardware/interfaces/boot/1.1/IBootControl.hal
package android.hardware.boot@1.1;
interface IBootControl extends @1.0::IBootControl {
    setSnapshotMergeStatus(MergeStatus status)
        generates (bool success);
    getSnapshotMergeStatus()
        generates (MergeStatus status);
}
// Recommended implementation

Return<bool> BootControl::setSnapshotMergeStatus(MergeStatus v) {
    // Write value to persistent storage
    // e.g. misc partition (using libbootloader_message)
    // bootloader rejects wipe when status is SNAPSHOTTED
    // or MERGING
}

Zmiany Fstab

Integralność partycji metadanych ma zasadnicze znaczenie dla procesu rozruchu, zwłaszcza zaraz po zastosowaniu aktualizacji OTA. Tak więc partycja metadanych musi zostać sprawdzona przed zamontowaniem jej przez first_stage_init . Aby upewnić się, że tak się stanie, dodaj flagę check fs_mgr do wpisu dla /metadata . Poniżej przedstawiono przykład:

/dev/block/by-name/metadata /metadata ext4 noatime,nosuid,nodev,discard,sync wait,formattable,first_stage_mount,check

Wymagania jądra

Aby włączyć migawkę, ustaw CONFIG_DM_SNAPSHOT na true .

W przypadku urządzeń korzystających z F2FS, dołącz flagę f2fs: export FS_NOCOW_FL do poprawki jądra użytkownika , aby naprawić przypinanie plików. Dołącz f2fs: obsługuje również łatkę do kernela z przypiętym plikiem .

Wirtualne A/B opiera się na funkcjach dodanych w jądrze w wersji 4.3: bit statusu przepełnienia w celach snapshot i snapshot-merge . Wszystkie urządzenia uruchamiane z systemem Android 9 lub nowszym powinny już mieć jądro w wersji 4.4 lub nowszej.

Aby włączyć skompresowane migawki, minimalna obsługiwana wersja jądra to 4.19. Ustaw CONFIG_DM_USER=m lub CONFIG_DM_USER=y . W przypadku korzystania z pierwszego (modułu) moduł musi być załadowany do ramdysku pierwszego stopnia. Można to osiągnąć poprzez dodanie następującej linii do Makefile urządzenia:

BOARD_GENERIC_RAMDISK_KERNEL_MODULES_LOAD := dm-user.ko

Doposażenie na urządzeniach aktualizujących do Androida 11

Podczas aktualizacji do systemu Android 11 urządzenia, które zostały uruchomione z partycjami dynamicznymi, mogą opcjonalnie doposażyć wirtualne A/B. Proces aktualizacji jest w większości taki sam jak w przypadku urządzeń uruchamianych z wirtualnym A/B, z pewnymi drobnymi różnicami:

  • Lokalizacja plików COW — w przypadku urządzeń uruchamiających klient OTA wykorzystuje całą dostępną pustą przestrzeń na superpartycji przed użyciem miejsca w /data . W przypadku urządzeń modernizowanych na superpartycji zawsze jest wystarczająco dużo miejsca, aby plik COW nigdy nie został utworzony w /data .

  • Flagi funkcji czasu kompilacji — w przypadku urządzeń modernizujących wirtualną A/B zarówno PRODUCT_VIRTUAL_AB_OTA , jak i PRODUCT_VIRTUAL_AB_OTA_RETROFIT mają wartość true , jak pokazano poniżej:

    (call inherit-product, \
        (SRC_TARGET_DIR)/product/virtual_ab_ota_retrofit.mk)
    
  • Rozmiar superpartycji — urządzenia uruchamiane z wirtualną A/B mogą zmniejszyć BOARD_SUPER_PARTITION_SIZE połowę, ponieważ gniazda B nie znajdują się w superpartycji. Urządzenia modernizujące wirtualne A/B zachowują rozmiar starej superpartycji, więc BOARD_SUPER_PARTITION_SIZE jest większa lub równa 2 * suma (rozmiar grup aktualizacji) + narzut , który z kolei jest większy lub równy 2 * suma (rozmiar partycji) + koszty ogólne .

Zmiany w bootloaderze

Podczas scalania aktualizacji /data przechowuje jedyne całe wystąpienie systemu operacyjnego Android. Po rozpoczęciu migracji natywne partycje system , vendor i product są niekompletne do czasu zakończenia kopiowania. Jeśli podczas tego procesu urządzenie zostanie zresetowane do ustawień fabrycznych, przez odzyskiwanie lub przez okno dialogowe Ustawienia systemowe, nie będzie można go uruchomić.

Przed skasowaniem /data , zakończ scalanie w trybie odzyskiwania lub przywracania w zależności od stanu urządzenia:

  • Jeśli nowa kompilacja została wcześniej pomyślnie uruchomiona, zakończ migrację.
  • W przeciwnym razie przywróć do starego gniazda:
    • W przypadku partycji dynamicznych przywróć poprzedni stan.
    • W przypadku partycji statycznych ustaw aktywne gniazdo na stare gniazdo.

Zarówno bootloader, jak i fastbootd mogą usunąć partycję /data , jeśli urządzenie jest odblokowane. Podczas gdy fastbootd może wymusić zakończenie migracji, bootloader nie. Bootloader nie wie, czy trwa scalanie ani jakie bloki w /data stanowią partycje systemu operacyjnego. Urządzenia muszą uniemożliwić użytkownikowi nieświadome wyłączenie urządzenia (zamurowanie), wykonując następujące czynności:

  1. Zaimplementuj warstwę HAL kontroli rozruchu, aby program ładujący mógł odczytać wartość ustawioną przez setSnapshotMergeStatus() .
  2. Jeśli status scalenia to MERGING , lub jeśli status scalenia to SNAPSHOTTED i gniazdo zmieniło się na nowo zaktualizowane, żądania userdata danych użytkownika , metadata lub partycji przechowującej stan scalenia muszą zostać odrzucone w bootloaderze.
  3. Zaimplementuj polecenie fastboot snapshot-update cancel , aby użytkownicy mogli zasygnalizować programowi rozruchowemu, że chcą ominąć ten mechanizm ochrony.
  4. Zmodyfikuj niestandardowe narzędzia lub skrypty do flashowania, aby fastboot snapshot-update cancel podczas flashowania całego urządzenia. Jest to bezpieczne, ponieważ flashowanie całego urządzenia usuwa OTA. Narzędzia mogą wykryć to polecenie w czasie wykonywania, implementując fastboot getvar snapshot-update-status . To polecenie pomaga rozróżnić warunki błędów.

Przykład

struct VirtualAbState {
    uint8_t StructVersion;
    uint8_t MergeStatus;
    uint8_t SourceSlot;
};

bool ShouldPreventUserdataWipe() {
    VirtualAbState state;
    if (!ReadVirtualAbState(&state)) ...
    return state.MergeStatus == MergeStatus::MERGING ||
           (state.MergeStatus == MergeStatus::SNAPSHOTTED &&
            state.SourceSlot != CurrentSlot()));
}

Zmiany w oprzyrządowaniu Fastboot

Android 11 wprowadza następujące zmiany w protokole fastboot:

  • getvar snapshot-update-status — Zwraca wartość, którą HAL kontroli rozruchu przekazał bootloaderowi:
    • Jeśli stan to MERGING , bootloader musi zwrócić merging .
    • Jeśli stan to SNAPSHOTTED , bootloader musi zwrócić snapshotted .
    • W przeciwnym razie bootloader musi zwrócić none .
  • snapshot-update merge — kończy operację scalania, w razie potrzeby uruchamiając w trybie odzyskiwania/szybkiego rozruchu. To polecenie jest poprawne tylko wtedy, gdy snapshot-update-status to merging i jest obsługiwane tylko w fastbootd.
  • snapshot-update cancel — Ustawia stan scalania warstwy HAL kontroli rozruchu na CANCELLED . To polecenie jest nieprawidłowe, gdy urządzenie jest zablokowane.
  • erase or wipeerase lub wipe metadata , userdata użytkownika lub partycji ze statusem scalania dla kontroli rozruchu HAL powinno sprawdzać stan scalania migawek. Jeśli stan to MERGING lub SNAPSHOTTED , urządzenie powinno przerwać operację.
  • set_active — Polecenie set_active zmieniające aktywne gniazdo powinno sprawdzać stan scalania migawek. Jeśli status to MERGING , urządzenie powinno przerwać operację. Slot można bezpiecznie zmienić w stanie SNAPSHOTTED .

Zmiany te mają na celu zapobieganie przypadkowemu uniemożliwieniu rozruchu urządzenia, ale mogą one zakłócać działanie zautomatyzowanych narzędzi. Gdy polecenia są używane jako składnik flashowania wszystkich partycji, na przykład uruchamianie fastboot flashall , zaleca się użycie następującego przepływu:

  1. Zapytanie getvar snapshot-update-status .
  2. W przypadku merging lub snapshotted , snapshot-update cancel .
  3. Kontynuuj miganie kroków.

Zmniejszenie wymagań dotyczących przechowywania

Urządzenia, które nie mają pełnej pamięci A/B przydzielonej w trybie super i spodziewają się używać /data w razie potrzeby, zdecydowanie zaleca się korzystanie z narzędzia do mapowania bloków. Narzędzie do mapowania bloków zapewnia spójną alokację bloków między kompilacjami, redukując niepotrzebne zapisy w migawce. Jest to udokumentowane w części Redukcja rozmiaru OTA .