Android ma dwa mechanizmy aktualizacji: aktualizacje A/B (bezproblemowe) i aktualizacje inne niż A/B. Aby zmniejszyć złożoność kodu i usprawnić proces aktualizacji, w systemie Android 11 oba mechanizmy są zunifikowane za pomocą wirtualnego A/B, aby zapewnić płynne aktualizacje na wszystkich urządzeniach przy zminimalizowanych kosztach przechowywania. Android 12 oferuje opcję kompresji Virtual A/B do kompresji zrzutów partycji. Zarówno w systemie Android 11, jak i Android 12 obowiązują następujące zasady:
- Wirtualne aktualizacje A/B są płynne jak aktualizacje A/B. Wirtualne aktualizacje A/B minimalizują czas, w którym urządzenie jest w trybie offline i nie nadaje się do użytku.
- Aktualizacje wirtualnych A/B można wycofać . Jeśli nowy system operacyjny nie uruchomi się, urządzenia automatycznie przywrócą poprzednią wersję.
- Aktualizacje wirtualne A/B zajmują minimalną ilość dodatkowego miejsca , duplikując tylko partycje używane przez program ładujący. Inne partycje, które można aktualizować, są zapisywane w migawkach .
Tło i terminologia
W tej sekcji zdefiniowano terminologię i opisano technologię obsługującą wirtualne A/B.
Urządzenie do mapowania
Device-mapper to wirtualna warstwa bloków Linuksa, często używana w Androidzie. W przypadku partycji dynamicznych partycje takie jak /system
są stosem urządzeń warstwowych:
- Na dole stosu znajduje się fizyczna superpartycja (na przykład
/dev/block/by-name/super
) . - W środku znajduje się urządzenie
dm-linear
, określające, które bloki w super partycji tworzą daną partycję. Pojawia się jako/dev/block/mapper/system_[a|b]
na urządzeniu A/B lub/dev/block/mapper/system
na urządzeniu innym niż A/B. - Na górze znajduje się urządzenie
dm-verity
, stworzone dla zweryfikowanych partycji. To urządzenie sprawdza, czy bloki na urządzeniudm-linear
są poprawnie podpisane. Pojawia się jako/dev/block/mapper/system-verity
i jest źródłem punktu montowania/system
.
Rysunek 1 pokazuje, jak wygląda stos pod punktem montowania /system
.
Rysunek 1. Stos pod /punktem montowania systemu
dm-migawka
Wirtualne A/B opiera się na dm-snapshot
, module mapowania urządzenia do tworzenia migawek stanu urządzenia pamięci masowej. Podczas korzystania z dm-snapshot
w grze dostępne są cztery urządzenia:
- Urządzeniem podstawowym jest urządzenie, na którym wykonano migawkę. Na tej stronie urządzenie podstawowe jest zawsze partycją dynamiczną, taką jak system lub dostawca.
- Urządzenie typu copy-on-write (COW) służące do rejestrowania zmian w urządzeniu podstawowym. Może mieć dowolny rozmiar, ale musi być wystarczająco duży, aby pomieścić wszystkie zmiany w urządzeniu podstawowym.
- Urządzenie do zrzutu obrazu jest tworzone przy użyciu celu
snapshot
. Zapisy do urządzenia migawkowego są zapisywane na urządzeniu COW. Odczyty z urządzenia migawkowego odczytane z urządzenia podstawowego lub urządzenia COW, w zależności od tego, czy dane, do których uzyskuje się dostęp, zostały zmienione przez migawkę. - Urządzenie źródłowe jest tworzone przy użyciu docelowego miejsca pochodzenia
snapshot-origin
. Odczytuje do urządzenia źródłowego odczytywane bezpośrednio z urządzenia podstawowego. Zapisuje w urządzeniu źródłowym, zapisuje bezpośrednio w urządzeniu podstawowym, ale kopia zapasowa oryginalnych danych jest tworzona przez zapis na urządzeniu COW.
Rysunek 2. Mapowanie urządzeń dla dm-snapshot
Skompresowane migawki
W systemie Android 12 i nowszych, ponieważ wymagania dotyczące miejsca na partycji /data
mogą być wysokie, możesz włączyć skompresowane migawki w swojej kompilacji, aby sprostać wyższym wymaganiom dotyczącym miejsca na partycji /data
.
Wirtualne skompresowane migawki A/B są oparte na następujących składnikach dostępnych w systemie Android 12 i nowszych:
-
dm-user
, moduł jądra podobny do FUSE, który pozwala przestrzeni użytkownika na implementację urządzeń blokowych. -
snapuserd
, demon przestrzeni użytkownika do implementacji nowego formatu migawki.
Te składniki umożliwiają kompresję. Inne niezbędne zmiany wprowadzone w celu zaimplementowania możliwości skompresowanych migawek są podane w następnych sekcjach: Format COW dla skompresowanych migawek , dm-user i Snapuserd .
Format COW dla skompresowanych migawek
W systemie Android 12 i nowszych skompresowane migawki używają formatu COW. Podobnie do wbudowanego formatu jądra używanego do nieskompresowanych migawek, format COW dla skompresowanych migawek zawiera naprzemienne sekcje metadanych i danych. Metadane oryginalnego formatu zezwalały tylko na operacje zastępowania : Zastąp blok X w obrazie podstawowym zawartością bloku Y w migawce. Skompresowany format COW migawek jest bardziej wyrazisty i obsługuje następujące operacje:
- Kopiuj : Blok X w urządzeniu podstawowym należy zastąpić blokiem Y w urządzeniu podstawowym.
- Zamień : Blok X w urządzeniu podstawowym powinien zostać zastąpiony zawartością bloku Y w migawce. Każdy z tych bloków jest skompresowany w gz.
- Zero : Blok X w urządzeniu podstawowym należy zastąpić wszystkimi zerami.
- XOR : Urządzenie COW przechowuje skompresowane bajty XOR między blokiem X a blokiem Y. (Dostępne w systemie Android 13 i nowszych.)
Pełne aktualizacje OTA składają się tylko z operacji wymiany i zerowania . Przyrostowe aktualizacje OTA mogą dodatkowo zawierać operacje kopiowania .
dm-user w Androidzie 12
Moduł jądra dm-user umożliwia userspace
implementację urządzeń blokowych mapowania urządzeń. Wpis tabeli dm-user tworzy różne urządzenia w /dev/dm-user/<control-name>
. Proces userspace
może odpytywać urządzenie, aby otrzymać żądania odczytu i zapisu z jądra. Każde żądanie ma skojarzony bufor dla przestrzeni użytkownika do wypełnienia (dla odczytu) lub propagacji (dla zapisu).
Moduł jądra dm-user
zapewnia nowy, widoczny dla użytkownika interfejs do jądra, który nie jest częścią podstawowego kodu kernel.org. Do tego czasu Google zastrzega sobie prawo do modyfikacji interfejsu dm-user
w systemie Android.
snapuserd
Komponent przestrzeni użytkownika snapuserd
do dm-user
implementuje kompresję Virtual A/B.
W nieskompresowanej wersji Virtual A/B (w systemie Android 11 i niższych lub w systemie Android 12 bez opcji skompresowanej migawki) urządzenie COW jest plikiem surowym. Gdy kompresja jest włączona, COW działa zamiast tego jako urządzenie dm-user
, które jest połączone z instancją demona snapuserd
.
Jądro nie używa nowego formatu COW. Tak więc komponent snapuserd
tłumaczy żądania między formatem Android COW a wbudowanym formatem jądra:
Rysunek 3. Schemat działania snapuserda jako tłumacza między formatami Android i Kernel COW
Ta translacja i dekompresja nigdy nie występują na dysku. Komponent snapuserd
przechwytuje odczyty i zapisy COW, które występują w jądrze i implementuje je przy użyciu formatu Android COW.
Kompresja XOR
W przypadku urządzeń uruchamianych z systemem Android 13 i nowszym funkcja kompresji XOR, która jest domyślnie włączona, umożliwia przechowywanie migawek przestrzeni użytkownika skompresowanych bajtów XOR między starymi blokami a nowymi blokami. Gdy podczas aktualizacji Virtual A/B zmienia się tylko kilka bajtów w bloku, schemat pamięci masowej kompresji XOR zużywa mniej miejsca niż domyślny schemat pamięci masowej, ponieważ migawki nie przechowują pełnych 4 KB bajtów. To zmniejszenie rozmiaru migawki jest możliwe, ponieważ dane XOR zawierają wiele zer i są łatwiejsze do kompresji niż nieprzetworzone dane blokowe. Na urządzeniach Pixel kompresja XOR zmniejsza rozmiar migawki o 25% do 40%.
W przypadku urządzeń uaktualniających do systemu Android 13 lub nowszego kompresja XOR musi być włączona. Aby uzyskać szczegółowe informacje, zobacz Kompresja XOR .
Wirtualne procesy kompresji A/B
Ta sekcja zawiera szczegółowe informacje na temat procesu kompresji Virtual A/B używanego w systemach Android 13 i Android 12.
Odczytywanie metadanych (Android 12)
Metadane są konstruowane przez demona snapuserd
. Metadane to przede wszystkim mapowanie dwóch identyfikatorów, każdy po 8 bajtów, które reprezentują sektory, które mają zostać połączone. W dm-snapshot
nazywa się to disk_exception
.
struct disk_exception {
uint64_t old_chunk;
uint64_t new_chunk;
};
Wyjątek dysku jest używany, gdy stary fragment danych jest zastępowany przez nowy.
Demon snapuserd
odczytuje wewnętrzny plik COW przez bibliotekę COW i konstruuje metadane dla każdej z operacji COW obecnych w pliku COW.
Odczyty metadanych są inicjowane z dm-snapshot
w jądrze podczas tworzenia urządzenia dm- dm- snapshot
.
Poniższy rysunek przedstawia diagram sekwencji dla ścieżki we/wy do budowy metadanych.
Rysunek 4. Przebieg sekwencji dla ścieżki IO w konstrukcji metadanych
Scalanie (Android 12)
Po zakończeniu procesu uruchamiania mechanizm aktualizacji oznacza gniazdo jako pomyślne uruchomienie i inicjuje scalenie, przełączając cel dm-snapshot
na cel dm-snapshot-merge
.
dm-snapshot
przechodzi przez metadane i inicjuje scalanie we/wy dla każdego wyjątku dysku. Ogólny przegląd ścieżki scalania we/wy pokazano poniżej.
Rysunek 5. Przegląd ścieżki scalania we/wy
Jeśli urządzenie zostanie ponownie uruchomione podczas procesu scalania, scalanie zostanie wznowione przy następnym ponownym uruchomieniu, a scalanie zostanie zakończone.
Warstwy urządzenie-mapper
W przypadku urządzeń uruchamianych z systemem Android 13 i nowszym procesy scalania migawek i migawek w kompresji Virtual A/B są wykonywane przez składnik przestrzeni użytkownika snapuserd
. W przypadku urządzeń uaktualniających do systemu Android 13 lub nowszego ta funkcja musi być włączona. Aby uzyskać szczegółowe informacje, zobacz Scalanie przestrzeni użytkownika .
Poniżej opisano proces kompresji Virtual A/B:
- Struktura montuje partycję
/system
z urządzeniadm-verity
, które jest ułożone w stos na urządzeniudm-user
. Oznacza to, że każde I/O z głównego systemu plików jest kierowane dodm-user
. -
dm-user
kieruje I/O do demonasnapuserd
w przestrzeni użytkownika, który obsługuje żądania I/O. - Po zakończeniu operacji scalania framework zwija
dm-verity
nadm-linear
(system_base
) i usuwadm-user
.
Rysunek 6. Wirtualny proces kompresji A/B
Proces scalania migawek można przerwać. Jeśli urządzenie zostanie ponownie uruchomione podczas procesu scalania, proces scalania zostanie wznowiony po ponownym uruchomieniu.
Przejścia początkowe
Podczas uruchamiania ze skompresowanymi migawkami, init pierwszego etapu musi uruchomić snapuserd
, aby zamontować partycje. Stwarza to problem: gdy sepolicy
są ładowane i egzekwowane, snapuserd
jest umieszczany w niewłaściwym kontekście, a jego żądania odczytu kończą się niepowodzeniem, z odmowami selinuksa.
Aby rozwiązać ten problem, snapuserd
przechodzi w lock-step z init
, w następujący sposób:
-
snapuserd
init
ramdysku i zapisuje w nim otwarty deskryptor pliku w zmiennej środowiskowej. - W pierwszym etapie
init
przełącza główny system plików na partycję systemową, a następnie wykonuje kopię systemowąinit
. - Systemowa kopia
init
odczytuje połączoną sepolitykę w łańcuch. -
Init
wywołujemlock()
na wszystkich stronach obsługiwanych przez ext4. Następnie dezaktywuje wszystkie tabele mapowania urządzeń dla urządzeń migawkowych i zatrzymujesnapuserd
. Po tym nie wolno czytać z partycji, ponieważ powoduje to zakleszczenie. - Używając otwartego deskryptora do kopii
snapuserd
na ramdysku,init
ponownie uruchamia demona z poprawnym kontekstem selinux. Tabele mapowania urządzeń dla urządzeń migawek są ponownie aktywowane. - Init wywołuje
munlockall()
- można ponownie wykonać IO.
Wykorzystanie przestrzeni
Poniższa tabela zawiera porównanie wykorzystania miejsca przez różne mechanizmy OTA przy użyciu systemów operacyjnych Pixel i rozmiarów OTA.
Wpływ rozmiaru | nie-A/B | A/B | Wirtualne A/B | Wirtualne A/B (skompresowane) |
---|---|---|---|---|
Oryginalny obraz fabryczny | 4,5 GB super (obraz 3,8 GB + zarezerwowane 700 MB) 1 | Super 9 GB (zarezerwowane 3,8 G + 700 M, na dwa gniazda) | 4,5 GB super (obraz 3,8 GB + zarezerwowane 700 MB) | 4,5 GB super (obraz 3,8 GB + zarezerwowane 700 MB) |
Inne partycje statyczne | /Pamięć podręczna | Nic | Nic | Nic |
Dodatkowa pamięć podczas OTA (przestrzeń zwracana po zastosowaniu OTA) | 1,4 GB na /dane | 0 | 3,8 GB 2 na /dane | 2,1 GB 2 na /dane |
Całkowita pamięć wymagana do zastosowania OTA | 5,9 GB 3 (super i dane) | 9 GB (super) | 8,3 GB 3 (super i dane) | 6,6 GB 3 (super i dane) |
1 Wskazuje zakładany układ na podstawie mapowania pikseli.
2 Zakłada, że nowy obraz systemu ma taki sam rozmiar jak oryginalny.
3 Wymagane miejsce jest przejściowe do ponownego uruchomienia.
Aby zaimplementować Virtual A/B lub skorzystać z funkcji skompresowanych migawek, zobacz Implementacja Virtual A/B