Czy Google używa aktualizacji A/B OTA na jakichś urządzeniach?
Tak. Nazwa marketingowa aktualizacji A/B to bezproblemowe aktualizacje. Telefony Pixel i Pixel XL
z października 2016 r. były dostarczane z aktualizacjami A/B, a wszystkie Chromebooki używają tej samej
update_engine
implementacji A/B. Niezbędna implementacja kodu platformy jest publiczna w Androidzie 7.1 i
nowszych.
Dlaczego aktualizacje A/B OTA są lepsze?
Aktualizacje A/B OTA zapewniają lepsze wrażenia użytkownika podczas aktualizacji. Pomiary z comiesięcznych aktualizacji zabezpieczeń pokazują, że ta funkcja już się sprawdziła: w maju 2017 r. 95% właścicieli Pixeli korzystało z najnowszej aktualizacji zabezpieczeń po miesiącu, w porównaniu z 87% użytkowników Nexusów, a użytkownicy Pixeli aktualizują urządzenia szybciej niż użytkownicy Nexusów. Błędy podczas aktualizacji OTA nie powodują już, że urządzenie nie uruchamia się. Dopóki nowy obraz systemu nie zostanie pomyślnie uruchomiony, Android zachowuje możliwość powrotu do poprzedniego działającego obrazu systemu.
Co to jest system_other?
Aplikacje są przechowywane w plikach .apk, które są w rzeczywistości archiwami ZIP. Każdy plik .apk zawiera co najmniej 1 plik .dex z przenośnym kodem bajtowym Dalvik. Plik .odex (zoptymalizowany .dex) jest przechowywany oddzielnie od pliku .apk i może zawierać kod maszynowy specyficzny dla urządzenia. Jeśli dostępny jest plik .odex, Android może uruchamiać aplikacje z szybkością kompilacji AOT bez konieczności kompilowania kodu przy każdym uruchomieniu aplikacji. Plik .odex nie jest bezwzględnie konieczny: Android może bezpośrednio uruchamiać kod .dex za pomocą interpretacji lub kompilacji Just-In-Time (JIT), ale plik .odex zapewnia najlepsze połączenie szybkości uruchamiania i szybkości działania, jeśli jest dostępna wystarczająca ilość miejsca.
Przykład: w przypadku pliku installed-files.txt z Nexusa 6P z Androidem 7.1 i całkowitym rozmiarem obrazu systemu 2628 MiB (2755792836 bajtów) podział największych elementów wpływających na ogólny rozmiar obrazu systemu według typu pliku jest następujący:
| .odex | 1391770312 bajtów | 50,5% |
| .apk | 846878259 bajtów | 30,7% |
| .so (natywny kod C/C++) | 202162479 bajtów | 7,3% |
| pliki .oat / obrazy .art | 163892188 bajtów | 5,9% |
| Czcionki | 38952361 bajtów | 1,4% |
| dane regionalne icu | 27468687 bajtów | 0,9% |
Te dane są podobne w przypadku innych urządzeń, więc na urządzeniach Nexus/Pixel pliki .odex zajmują
około połowy partycji systemowej. Oznaczało to, że mogliśmy nadal używać systemu ext4, ale zapisywać
pliki .odex na partycji B w fabryce, a następnie kopiować je do /data przy
pierwszym uruchomieniu. Rzeczywista ilość miejsca używanego w przypadku ext4 A/B jest taka sama jak w przypadku SquashFS A/B, ponieważ gdybyśmy
używali SquashFS, dostarczylibyśmy wstępnie zoptymalizowane pliki .odex w systemie_a zamiast w
systemie_b.
Czy kopiowanie plików .odex do /data oznacza, że miejsce zaoszczędzone w /system jest tracone w /data?
Niezupełnie. Na Pixelu większość miejsca zajmowanego przez pliki .odex jest przeznaczona na aplikacje, które zwykle
znajdują się w /data. Te aplikacje pobierają aktualizacje z Google Play, więc pliki .apk i .odex
w obrazie systemu są nieużywane przez większość czasu działania urządzenia. Takie pliki można całkowicie wykluczyć
i zastąpić małymi plikami .odex opartymi na profilach, gdy użytkownik faktycznie używa każdej
aplikacji (dzięki czemu nie zajmują miejsca w przypadku aplikacji, których użytkownik nie używa). Więcej informacji znajdziesz w prezentacji The Evolution of Art z Google
I/O 2016.
Porównanie jest trudne z kilku kluczowych powodów:
-
Aplikacje aktualizowane przez Google Play zawsze miały pliki .odex w
/dataod momentu otrzymania pierwszej aktualizacji. - Aplikacje, których użytkownik nie uruchamia, w ogóle nie potrzebują pliku .odex.
- Kompilacja oparta na profilach generuje mniejsze pliki .odex niż kompilacja AOT (ponieważ ta pierwsza optymalizuje tylko kod krytyczny dla wydajności).
Więcej informacji o opcjach dostrajania dostępnych dla producentów OEM znajdziesz w artykule Konfigurowanie ART.
Czy w /data nie ma 2 kopii plików .odex?
To trochę bardziej skomplikowane ... Po zapisaniu nowego obrazu systemu nowa
wersja dex2oat jest uruchamiana w stosunku do nowych plików .dex, aby wygenerować nowe pliki .odex. Dzieje się to, gdy stary system jest nadal uruchomiony, więc stare i nowe pliki .odex znajdują się jednocześnie w /data.
Kod w OtaDexoptService (frameworks/base/+/android17-release/services/core/java/com/android/server/pm/OtaDexoptService.java) wywołuje getAvailableSpace przed optymalizacją każdego pakietu, aby uniknąć przepełnienia
/data. Pamiętaj, że dostępne miejsce jest tu nadal konserwatywne: jest to ilość
miejsca pozostała przed osiągnięciem zwykłego progu małej ilości miejsca w systemie (mierzonego zarówno jako
procent, jak i liczba bajtów). Jeśli więc /data jest pełne, nie będzie 2 kopii każdego pliku .odex. Ten sam kod ma też BULK_DELETE_THRESHOLD: jeśli urządzenie zbliży się do wypełnienia dostępnego miejsca (jak opisano powyżej), pliki .odex należące do nieużywanych aplikacji zostaną usunięte. To kolejny przypadek, w którym nie ma 2 kopii każdego pliku .odex.
W najgorszym przypadku, gdy /data jest całkowicie pełne, aktualizacja czeka, aż urządzenie uruchomi się w nowym systemie i nie będzie już potrzebować plików .odex starego systemu. Zajmuje się tym
PackageManager: (frameworks/base/+/android17-release/services/core/java/com/android/server/pm/PackageManagerService.java#7215). Po pomyślnym uruchomieniu nowego systemu installd (frameworks/native/+/android17-release/cmds/installd/dexopt.cpp#2422) może usunąć pliki .odex używane przez stary system, przywracając urządzenie do
stanu stabilnego, w którym jest tylko 1 kopia.
Chociaż jest możliwe, że /data zawiera 2 kopie wszystkich plików .odex,
(a) jest to tymczasowe i (b) występuje tylko wtedy, gdy masz dużo wolnego miejsca w
/data anyway. Poza aktualizacją jest tylko 1 kopia. W ramach ogólnych funkcji odporności ART nigdy nie wypełni /data plikami .odex (ponieważ byłby to problem również w systemie innym niż A/B).
Czy to wszystko zapisywanie i kopiowanie nie zwiększa zużycia pamięci flash?
Przepisywana jest tylko niewielka część pamięci flash: pełna aktualizacja systemu Pixel zapisuje około 2,3 GiB. (Aplikacje są też ponownie kompilowane, ale dotyczy to też systemów innych niż A/B). Tradycyjnie pełne aktualizacje OTA oparte na blokach zapisywały podobną ilość danych, więc współczynniki zużycia pamięci flash powinny być podobne.
Czy flashowanie 2 partycji systemowych wydłuża czas flashowania fabrycznego?
Nie. Rozmiar obrazu systemu Pixel nie zwiększył się (został tylko podzielony na 2 partycje).
Czy przechowywanie plików .odex na partycji B nie spowalnia ponownego uruchamiania po przywróceniu danych fabrycznych?
Tak. Jeśli używasz urządzenia, na którym przeprowadzono aktualizację OTA i przywrócono dane fabryczne, pierwsze ponowne uruchomienie będzie wolniejsze niż zwykle (1 min 40 s zamiast 40 s na Pixelu XL), ponieważ pliki .odex zostaną utracone z partycji B po pierwszej aktualizacji OTA i nie będzie można ich skopiować do /data. To jest kompromis.
Przywracanie danych fabrycznych powinno być rzadką operacją w porównaniu ze zwykłym uruchamianiem, więc czas potrzebny na jej wykonanie
jest mniej ważny. (Nie dotyczy to użytkowników ani recenzentów, którzy otrzymują urządzenie z
fabryki, ponieważ w takim przypadku partycja B jest dostępna). Użycie kompilatora JIT oznacza, że nie
musimy ponownie kompilować wszystkiego, więc nie jest tak źle, jak mogłoby się wydawać. Można też
oznaczyć aplikacje jako wymagające kompilacji AOT za pomocą
coreApp="true" w pliku manifestu: (frameworks/base/+/android17-release/packages/SystemUI/AndroidManifest.xml#23). Jest to obecnie używane przez system_server, ponieważ ze względów bezpieczeństwa nie może on używać kompilacji JIT.
Czy przechowywanie plików .odex w /data zamiast w /system nie spowalnia ponownego uruchamiania po aktualizacji OTA?
Nie. Jak wyjaśniono powyżej, nowa wersja dex2oat jest uruchamiana, gdy stary obraz systemu jest nadal uruchomiony, aby wygenerować pliki, które będą potrzebne nowemu systemowi. Aktualizacja nie jest uznawana za dostępną, dopóki to nie zostanie zrobione.
Czy możemy (powinniśmy) dostarczać urządzenia A/B o pojemności 32 GiB? 16GiB? 8GiB?
32 GiB działa dobrze, co zostało potwierdzone na Pixelu, a 320 MiB z 16 GiB oznacza zmniejszenie o 2%. Podobnie 320 MiB z 8 GiB oznacza zmniejszenie o 4%. Oczywiście A/B nie byłoby zalecanym rozwiązaniem na urządzeniach z 4 GiB, ponieważ narzut 320 MiB to prawie 10% całkowitej dostępnej przestrzeni.
Czy AVB2.0 wymaga aktualizacji A/B OTA?
Nie. Android weryfikacja podczas uruchamiania zawsze wymagał aktualizacji opartych na blokach, ale niekoniecznie aktualizacji A/B.
Czy aktualizacje A/B OTA wymagają AVB2.0?
Nie.
Czy aktualizacje A/B OTA naruszają ochronę przed cofnięciem AVB2.0?
Nie. Wynika to z nieporozumienia, ponieważ jeśli system A/B nie uruchomi się w nowym obrazie systemu automatycznie (po pewnej liczbie prób określonej przez program rozruchowy) powróci do „poprzedniego” obrazu systemu. Kluczowe jest jednak to, że "poprzedni" w sensie A/B jest w rzeczywistości nadal "bieżącym" obrazem systemu. Gdy tylko urządzenie pomyślnie uruchomi nowy obraz, włącza się ochrona przed cofnięciem, która uniemożliwia powrót. Dopóki jednak nie uruchomisz pomyślnie nowego obrazu, ochrona przed cofnięciem nie uzna go za bieżący obraz systemu.
Czy instalowanie aktualizacji podczas działania systemu nie jest powolne?
W przypadku aktualizacji innych niż A/B celem jest jak najszybsze zainstalowanie aktualizacji, ponieważ użytkownik czeka i nie może korzystać z urządzenia podczas stosowania aktualizacji. W przypadku aktualizacji A/B jest odwrotnie: ponieważ użytkownik nadal korzysta z urządzenia, celem jest jak najmniejszy wpływ, więc aktualizacja jest celowo powolna. Dzięki logice w kliencie aktualizacji systemu Java (który w przypadku Google jest GmsCore, czyli podstawowym pakietem dostarczanym przez GMS) Android próbuje też wybrać czas, w którym użytkownicy w ogóle nie korzystają z urządzeń. Platforma obsługuje wstrzymywanie i wznawianie aktualizacji, a klient może używać tej funkcji, aby wstrzymać aktualizację, jeśli użytkownik zacznie korzystać z urządzenia, i wznowić ją, gdy urządzenie będzie ponownie bezczynne.
Podczas aktualizacji OTA występują 2 fazy, które są wyraźnie widoczne w interfejsie jako Krok 1 z 2 i Krok 2 z 2 pod paskiem postępu. Krok 1 odpowiada zapisywaniu bloków danych, a krok 2 to wstępna kompilacja plików .dex. Te 2 fazy różnią się znacznie pod względem wpływu na wydajność. Pierwsza faza to proste operacje wejścia/wyjścia. Wymaga to niewielkich zasobów (pamięci RAM, procesora, wejścia/wyjścia), ponieważ polega na powolnym kopiowaniu bloków.
Druga faza uruchamia dex2oat, aby wstępnie skompilować nowy obraz systemu. Oczywiście ma to mniej wyraźne granice wymagań, ponieważ kompiluje rzeczywiste aplikacje. Oczywiście kompilowanie dużej i złożonej aplikacji wymaga znacznie więcej pracy niż kompilowanie małej i prostej aplikacji, podczas gdy w fazie 1 nie ma bloków dysku, które byłyby większe lub bardziej złożone od innych.
Proces jest podobny do tego, gdy Google Play instaluje aktualizację aplikacji w tle przed wyświetleniem powiadomienia Zaktualizowano 5 aplikacji, co robi od lat.
Co się stanie, jeśli użytkownik faktycznie czeka na aktualizację?
Obecna implementacja w GmsCore nie rozróżnia aktualizacji w tle i aktualizacji zainicjowanych przez użytkownika, ale może to zrobić w przyszłości. Jeśli użytkownik wyraźnie poprosił o zainstalowanie aktualizacji lub ogląda ekran postępu aktualizacji, nadamy priorytet pracy nad aktualizacją, zakładając, że aktywnie czeka na jej zakończenie.
Co się stanie, jeśli nie uda się zastosować aktualizacji?
W przypadku aktualizacji innych niż A/B, jeśli nie udało się zastosować aktualizacji, użytkownik zwykle zostawał z urządzeniem, którego nie można było używać. Jedynym wyjątkiem był przypadek, gdy błąd wystąpił, zanim aplikacja się uruchomiła (ponieważ np. nie udało się zweryfikować pakietu). W przypadku aktualizacji A/B niepowodzenie zastosowania aktualizacji nie wpływa na aktualnie działający system. Aktualizację można po prostu ponowić później.