Zmniejsz rozmiar OTA

Na tej stronie opisano zmiany dodane do AOSP w celu ograniczenia niepotrzebnych zmian plików pomiędzy kompilacjami. Osoby wdrażające urządzenia, które utrzymują własne systemy kompilacji, mogą wykorzystać te informacje jako wskazówki dotyczące zmniejszania rozmiaru aktualizacji OTA.

Aktualizacje Androida OTA czasami zawierają zmienione pliki, które nie odpowiadają zmianom w kodzie. W rzeczywistości są to artefakty systemowe kompilacji. Może się to zdarzyć, gdy ten sam kod, zbudowany w różnym czasie, z różnych katalogów lub na różnych komputerach, generuje dużą liczbę zmienionych plików. Takie nadmiarowe pliki zwiększają rozmiar łatki OTA i utrudniają określenie, który kod został zmieniony.

Aby zawartość OTA była bardziej przejrzysta, AOSP zawiera zmiany w systemie kompilacji mające na celu zmniejszenie rozmiaru poprawek OTA. Wyeliminowano niepotrzebne zmiany plików pomiędzy kompilacjami, a aktualizacje OTA zawierają wyłącznie pliki związane z łatkami. AOSP zawiera także narzędzie do porównywania kompilacji , które odfiltrowuje typowe zmiany w plikach związane z kompilacją, aby zapewnić czystsze porównywanie plików kompilacji, oraz narzędzie do mapowania bloków , które pomaga zachować spójność alokacji bloków.

System kompilacji może tworzyć niepotrzebnie duże poprawki na kilka sposobów. Aby temu zaradzić, w systemie Android 8.0 i nowszych wersjach wprowadzono nowe funkcje zmniejszające rozmiar poprawki dla każdej różnicy plików. Ulepszenia, które zmniejszyły rozmiary pakietów aktualizacji OTA, obejmują:

  • Użycie Brotli , ogólnego algorytmu bezstratnej kompresji dla pełnych obrazów w aktualizacjach urządzeń innych niż A/B. Brotli można dostosować w celu optymalizacji kompresji. W przypadku większych aktualizacji składających się z dwóch lub więcej bloków w systemie plików (na przykład system.img ) producenci urządzeń lub partnerzy mogą dodawać własne algorytmy kompresji i mogą używać różnych algorytmów kompresji w różnych blokach tej samej aktualizacji.
  • Użycie rekompresji Puffin , deterministycznego narzędzia do łatania strumieni deflujących, które obsługuje funkcje kompresji i różnicowania na potrzeby generowania aktualizacji A/B OTA.
  • Zmiany w użyciu narzędzia generowania delta, takie jak sposób użycia biblioteki bsdiff do kompresowania poprawek. W systemie Android 9 i nowszych wersjach narzędzie bsdiff wybiera algorytm kompresji, który zapewni najlepsze wyniki kompresji dla łatki.
  • Ulepszenia update_engine spowodowały zmniejszenie zużycia pamięci podczas stosowania poprawek do aktualizacji urządzeń A/B.
  • Ulepszenia w dzieleniu dużych plików ZIP na potrzeby aktualizacji OTA opartych na blokach. Tryb w imgdiff dzieli duże pliki APK na podstawie nazw wpisów. Daje to mniejszą łatkę w porównaniu do liniowego dzielenia plików i używania narzędzia bsdiff do ich kompresji.

W poniższych sekcjach omówiono różne kwestie wpływające na rozmiary aktualizacji OTA, ich rozwiązania i przykłady implementacji w AOSP.

Kolejność plików

Problem : Systemy plików nie gwarantują kolejności plików, gdy są pytane o listę plików w katalogu, choć zazwyczaj jest ona taka sama w przypadku tego samego pobrania. Narzędzia takie jak ls domyślnie sortują wyniki, ale funkcja wieloznaczna używana w poleceniach takich jak find i make nie sortuje. Przed użyciem tych narzędzi należy posortować wyniki.

Rozwiązanie : Jeśli używasz narzędzi takich jak find i make z funkcją wieloznaczną, posortuj dane wyjściowe tych poleceń przed ich użyciem. W przypadku używania $(wildcard) lub $(shell find) w plikach Android.mk należy je również posortować. Niektóre narzędzia, takie jak Java, sortują dane wejściowe, dlatego przed sortowaniem plików sprawdź, czy narzędzie, którego używasz, jeszcze tego nie zrobiło.

Przykłady: Wiele instancji zostało naprawionych w podstawowym systemie kompilacji przy użyciu wbudowanego makra all-*-files-under , które obejmuje all-cpp-files-under (ponieważ kilka definicji zostało rozproszonych w innych plikach makefile). Aby uzyskać szczegółowe informacje, zapoznaj się z poniższymi informacjami:

Katalog kompilacji

Problem: Zmiana katalogu, w którym budowane są rzeczy, może spowodować różnice w plikach binarnych. Większość ścieżek w kompilacji Androida to ścieżki względne, więc __FILE__ w C/C++ nie stanowi problemu. Jednak symbole debugowania domyślnie kodują pełną ścieżkę, a .note.gnu.build-id jest generowany w wyniku mieszania wstępnie usuniętego pliku binarnego, więc zmieni się, jeśli zmienią się symbole debugowania.

Rozwiązanie: AOSP teraz sprawia, że ​​ścieżki debugowania są względne. Szczegółowe informacje można znaleźć w CL: https://android.googlesource.com/platform/build/+/6a66a887baadc9eb3d0d60e26f748b8453e27a02 .

Znaczniki czasu

Problem: Znaczniki czasu w wynikach kompilacji powodują niepotrzebne zmiany w plikach. Prawdopodobnie stanie się to w następujących lokalizacjach:

  • Makra __DATE__/__TIME__/__TIMESTAMP__ w kodzie C lub C++.
  • Sygnatury czasowe osadzone w archiwach zip.

Rozwiązania/przykłady: Aby usunąć znaczniki czasu z wyników kompilacji, skorzystaj z instrukcji podanych poniżej w __DATE__/__TIME__/__TIMESTAMP__ w C/C++. oraz Osadzone znaczniki czasu w archiwach .

__DATE__/__TIME__/__TIMESTAMP__ w C/C++

Te makra zawsze dają różne wyniki dla różnych kompilacji, więc nie używaj ich. Oto kilka opcji eliminacji tych makr:

Osadzone znaczniki czasu w archiwach (zip, jar)

W systemie Android 7.0 rozwiązano problem osadzonych znaczników czasu w archiwach zip, dodając -X do wszystkich zastosowań polecenia zip . Spowodowało to usunięcie UID/GID konstruktora i rozszerzonego znacznika czasu Uniksa z pliku zip.

Nowe narzędzie, ziptime (znajdujące się w /platform/build/+/main/tools/ziptime/ ) resetuje normalne znaczniki czasu w nagłówkach zip. Szczegółowe informacje można znaleźć w pliku README .

Narzędzie signapk ustawia znaczniki czasu dla plików APK, które mogą się różnić w zależności od strefy czasowej serwera. Szczegółowe informacje można znaleźć w instrukcji CL https://android.googlesource.com/platform/build/+/6c41036bcf35fe39162b50d27533f0f3bfab3028 .

Ciągi wersji

Problem: do ciągów wersji pakietu APK często dodawany był numer BUILD_NUMBER . Nawet jeśli w rezultacie w pliku APK nic się nie zmieni, plik APK nadal będzie inny.

Rozwiązanie: Usuń numer kompilacji z ciągu wersji APK.

Przykłady:

Włącz obliczanie prawdziwości na urządzeniu

Jeśli na Twoim urządzeniu włączona jest funkcja dm-verity , narzędzia OTA automatycznie pobiorą konfigurację Twojej weryfikacji i umożliwią jej obliczenie na urządzeniu. Umożliwia to obliczanie bloków rzeczywistości na urządzeniach z systemem Android zamiast przechowywania ich w postaci nieprzetworzonych bajtów w pakiecie OTA. Bloki Verity mogą zająć około 16MB na partycję 2GB.

Jednak obliczenie wiarygodności na urządzeniu może zająć dużo czasu. W szczególności kod korekcji błędów przekazywania może zająć dużo czasu. Na urządzeniach pikselowych zajmuje to zwykle do 10 minut. Na urządzeniach z niższej półki może to potrwać dłużej. Jeśli chcesz wyłączyć obliczanie prawdziwości na urządzeniu, ale nadal włączyć dm-verity, możesz to zrobić, przekazując --disable_fec_computation do narzędzia ota_from_target_files podczas generowania aktualizacji OTA. Ta flaga wyłącza obliczanie prawdziwości na urządzeniu podczas aktualizacji OTA. Skraca czas instalacji OTA, ale zwiększa rozmiar pakietu OTA. Jeśli na Twoim urządzeniu nie jest włączona funkcja dm-verity, przekazanie tej flagi nie przyniesie żadnego efektu.

Spójne narzędzia do tworzenia

Problem: Narzędzia generujące zainstalowane pliki muszą być spójne (dane wejściowe powinny zawsze dawać takie same dane wyjściowe).

Rozwiązania/przykłady: Wymagane były zmiany w następujących narzędziach do kompilacji:

Użyj narzędzia porównywania kompilacji

W przypadkach, gdy nie jest możliwe wyeliminowanie zmian w plikach związanych z kompilacją, AOSP zawiera narzędzie do porównywania kompilacji, target_files_diff.py , służące do porównywania dwóch pakietów plików. To narzędzie wykonuje rekurencyjną różnicę między dwiema kompilacjami, wykluczając typowe zmiany plików związane z kompilacją, takie jak

  • Oczekiwane zmiany w wynikach kompilacji (na przykład ze względu na zmianę numeru kompilacji).
  • Zmiany spowodowane znanymi problemami w bieżącym systemie kompilacji.

Aby użyć narzędzia kompilacji różnic, uruchom następującą komendę:

target_files_diff.py dir1 dir2

dir1 i dir2 to katalogi podstawowe zawierające wyodrębnione pliki docelowe dla każdej kompilacji.

Zachowaj spójność alokacji bloków

W przypadku danego pliku, chociaż jego zawartość pozostaje taka sama w dwóch kompilacjach, rzeczywiste bloki przechowujące dane mogły ulec zmianie. W rezultacie aktualizator musi wykonać niepotrzebne operacje we/wy, aby przenieść bloki w celu aktualizacji OTA.

W przypadku wirtualnej aktualizacji A/B OTA niepotrzebne wejścia/wyjścia mogą znacznie zwiększyć przestrzeń dyskową wymaganą do przechowywania migawki z funkcją kopiowania przy zapisie. W przypadku aktualizacji OTA innej niż A/B przesuwanie bloków w celu aktualizacji OTA wydłuża czas aktualizacji, ponieważ ze względu na przenoszenie bloków jest więcej wejść/wyjść.

Aby rozwiązać ten problem, w Androidzie 7.0 Google rozszerzyło narzędzie make_ext4fs , które pozwala zachować spójność alokacji bloków we wszystkich kompilacjach. Narzędzie make_ext4fs akceptuje opcjonalną flagę -d base_fs , która próbuje przydzielić pliki do tych samych bloków podczas generowania obrazu ext4 . Możesz wyodrębnić pliki mapowania bloków (takie jak pliki map base_fs ) z pliku zip plików docelowych poprzedniej kompilacji. Dla każdej partycji ext4 w katalogu IMAGES znajduje się plik .map (na przykład IMAGES/system.map odpowiada partycji system ). Te pliki base_fs można następnie wpisać i określić za pomocą PRODUCT_<partition>_BASE_FS_PATH , jak w tym przykładzie:

  PRODUCT_SYSTEM_BASE_FS_PATH := path/to/base_fs_files/base_system.map
  PRODUCT_SYSTEM_EXT_BASE_FS_PATH := path/to/base_fs_files/base_system_ext.map
  PRODUCT_VENDOR_BASE_FS_PATH := path/to/base_fs_files/base_vendor.map
  PRODUCT_PRODUCT_BASE_FS_PATH := path/to/base_fs_files/base_product.map
  PRODUCT_ODM_BASE_FS_PATH := path/to/base_fs_files/base_odm.map

Chociaż nie pomaga to w zmniejszeniu ogólnego rozmiaru pakietu OTA, poprawia wydajność aktualizacji OTA poprzez zmniejszenie ilości operacji we/wy. W przypadku wirtualnych aktualizacji A/B drastycznie zmniejsza ilość miejsca potrzebnego do zastosowania OTA.

Unikaj aktualizacji aplikacji

Oprócz minimalizowania różnic w kompilacjach możesz zmniejszyć rozmiary aktualizacji OTA, wykluczając aktualizacje aplikacji, które pobierają aktualizacje ze sklepów z aplikacjami. Pliki APK często stanowią znaczną część różnych partycji na urządzeniu. Uwzględnienie najnowszych wersji aplikacji aktualizowanych przez sklepy z aplikacjami w aktualizacji OTA może mieć duży wpływ na pakiety OTA i zapewniać niewielkie korzyści dla użytkownika. Zanim użytkownicy otrzymają pakiet OTA, mogą już mieć zaktualizowaną aplikację lub nawet nowszą wersję otrzymaną bezpośrednio ze sklepów z aplikacjami.