Zmniejszenie rozmiaru OTA

Ta strona opisuje zmiany dodane do AOSP w celu zmniejszenia niepotrzebnych zmian plików między kompilacjami. Realizatorzy urządzeń, którzy utrzymują własne systemy kompilacji, mogą wykorzystać te informacje jako wskazówki dotyczące zmniejszania rozmiaru aktualizacji OTA.

Aktualizacje Android OTA czasami zawierają zmienione pliki, które nie odpowiadają zmianom w kodzie. W rzeczywistości są artefaktami systemu budowania. Może się tak zdarzyć, gdy ten sam kod, zbudowany w różnym czasie, z różnych katalogów lub na różnych komputerach, tworzy dużą liczbę zmienionych plików. Takie nadmiarowe pliki zwiększają rozmiar łatki OTA i utrudniają określenie, który kod się zmienił.

Aby zawartość OTA była bardziej przejrzysta, AOSP zawiera zmiany systemu kompilacji zaprojektowane w celu zmniejszenia rozmiaru poprawek OTA. Niepotrzebne zmiany plików między kompilacjami zostały wyeliminowane, a aktualizacje OTA zawierają tylko pliki związane z poprawkami. AOSP zawiera również 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 na kilka sposobów tworzyć niepotrzebnie duże poprawki. Aby to złagodzić, w systemie Android 8.0 i nowszych zaimplementowano nowe funkcje zmniejszające rozmiar poprawki dla każdej różnicy plików. Ulepszenia, które zmniejszyły rozmiary pakietów aktualizacji OTA obejmują:

  • Wykorzystanie Brotli , algorytmu bezstratnej kompresji ogólnego przeznaczenia dla pełnych obrazów w aktualizacjach urządzeń innych niż A/B. Brotli można dostosować, aby zoptymalizować kompresję. W przypadku większych aktualizacji składających się z co najmniej dwóch 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.
  • Wykorzystanie rekompresji Puffin , deterministycznego narzędzia do łatania strumieni deflate, które obsługuje funkcje kompresji i diff dla generowania aktualizacji A/B OTA.
  • Zmiany w użyciu narzędzia do generowania delta, takie jak sposób użycia biblioteki bsdiff do kompresji łatek. W systemie Android 9 i nowszych narzędzie bsdiff wybiera algorytm kompresji, który zapewni najlepsze wyniki kompresji dla poprawki.
  • Ulepszenia mechanizmu update_engine spowodowały zmniejszenie zużycia pamięci, gdy poprawki są stosowane do aktualizacji urządzeń A/B.
  • Ulepszenia dzielenia dużych plików zip dla 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 problemy, które wpływają 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, chociaż zwykle jest ona taka sama dla tego samego zamówienia. Narzędzia takie jak ls domyślnie sortują wyniki, ale funkcja symboli wieloznacznych używana przez polecenia takie jak find i make nie sortuje. Przed użyciem tych narzędzi należy posortować wyniki.

Rozwiązanie : W przypadku korzystania z narzędzi, takich jak find i make z funkcją symboli wieloznacznych, posortuj dane wyjściowe tych poleceń przed ich użyciem. Używając $(wildcard) lub $(shell find) w plikach Android.mk , również je posortuj. Niektóre narzędzia, takie jak Java, sortują dane wejściowe, więc przed posortowaniem plików sprawdź, czy używane narzędzie jeszcze tego nie zrobiło.

Przykłady: Wiele instancji zostało naprawionych w systemie budowania rdzenia za pomocą wbudowanego makra all-*-files-under , które zawiera all-cpp-files-under (ponieważ kilka definicji zostało rozłożonych w innych plikach makefile). Aby uzyskać szczegółowe informacje, zapoznaj się z poniższym:

Katalog kompilacji

Problem: Zmiana katalogu, w którym budowane są rzeczy, może spowodować, że pliki binarne będą inne. Większość ścieżek w kompilacji systemu Android to ścieżki względne, więc __FILE__ w języku C/C++ nie stanowi problemu. Jednak symbole debugowania domyślnie kodują pełną nazwę ścieżki, a identyfikator .note.gnu.build-id jest generowany z haszowania wstępnie okrojonego pliku binarnego, więc zmieni się, jeśli zmienią się symbole debugowania.

Rozwiązanie: AOSP czyni teraz względnymi ścieżkami debugowania. Aby uzyskać szczegółowe informacje, zapoznaj się z CL: https://android.googlesource.com/platform/build/+/6a66a887baadc9eb3d0d60e26f748b8453e27a02 .

Znaczniki czasu

Problem: Sygnatury czasowe w danych wyjściowych kompilacji powodują niepotrzebne zmiany plików. Może się to zdarzyć w następujących lokalizacjach:

  • __DATE__/__TIME__/__TIMESTAMP__ makra w kodzie C lub C++.
  • Znaczniki czasu osadzone w archiwach zip.

Rozwiązania/Przykłady: Aby usunąć znaczniki czasu z danych wyjściowych kompilacji, użyj instrukcji podanych poniżej w __DATE__/__TIME__/__TIMESTAMP__ w C/C++. i Osadzone znaczniki czasu w archiwach .

__DATE__/__TIME__/__TIMESTAMP__ w C/C++

Te makra zawsze generują różne dane wyjściowe dla różnych kompilacji, więc nie używaj ich. Oto kilka opcji eliminacji tych makr:

Osadzone znaczniki czasu w archiwach (zip, jar)

Android 7.0 naprawił problem z osadzonymi znacznikami czasu w archiwach zip, dodając -X do wszystkich zastosowań polecenia zip . To usunęło UID/GID konstruktora i rozszerzony znacznik czasu Unixa z pliku zip.

Nowe narzędzie, ziptime (znajdujące się w /platform/build/+/master/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 zawiera dokument CL https://android.googlesource.com/platform/build/+/6c41036bcf35fe39162b50d27533f0f3bfab3028 .

Ciągi wersji

Problem: ciągi wersji APK często miały BUILD_NUMBER dodany do ich wersji zakodowanych na sztywno. Nawet jeśli nic się nie zmieni w pliku APK, w rezultacie plik APK nadal będzie inny.

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

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

Przykłady:

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

Jeśli dm-verity jest włączone na twoim urządzeniu, narzędzia OTA automatycznie pobierają twoją konfigurację Verity i włączają obliczanie prawdziwości na urządzeniu. Pozwala to na obliczanie prawdziwych bloków na urządzeniach z Androidem, zamiast przechowywania ich jako surowych bajtów w pakiecie OTA. Bloki Verity mogą wykorzystywać około 16 MB na partycję 2 GB.

Jednak przetwarzanie prawdziwoś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 wiarygodnoś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 poprawności na urządzeniu podczas aktualizacji OTA. Skraca czas instalacji OTA, ale zwiększa rozmiar pakietu OTA. Jeśli twoje urządzenie nie ma włączonej funkcji dm-verity, przekazanie tej flagi nie ma żadnego efektu.

Spójne narzędzia do budowania

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

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

Korzystanie z narzędzia porównywania kompilacji

W przypadkach, w których nie jest możliwe wyeliminowanie zmian w plikach związanych z kompilacją, AOSP zawiera narzędzie do porównywania kompilacji, target_files_diff.py , które można wykorzystać do porównywania dwóch pakietów plików. To narzędzie wykonuje rekurencyjne porównywanie dwóch kompilacji, z wyłączeniem typowych zmian w plikach związanych z kompilacją, takich jak

  • Oczekiwane zmiany w wynikach kompilacji (na przykład z powodu zmiany numeru kompilacji).
  • Zmiany spowodowane znanymi problemami w obecnym systemie kompilacji.

Aby użyć narzędzia do budowania różnic, uruchom następujące polecenie:

target_files_diff.py dir1 dir2

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

Utrzymywanie spójnej alokacji bloków

Dla danego pliku, chociaż jego zawartość pozostaje taka sama między dwoma kompilacjami, rzeczywiste bloki zawierające dane mogły ulec zmianie. W rezultacie aktualizator musi wykonać niepotrzebne operacje we/wy, aby przesunąć bloki w celu aktualizacji OTA.

W aktualizacji Virtual A/B OTA niepotrzebne operacje we/wy mogą znacznie zwiększyć przestrzeń dyskową wymaganą do przechowywania migawki kopiowania przy zapisie. W aktualizacji innej niż A/B OTA przesuwanie bloków w celu aktualizacji OTA przyczynia się do wydłużenia czasu aktualizacji, ponieważ jest więcej operacji we/wy z powodu ruchów bloków.

Aby rozwiązać ten problem, w systemie Android 7.0 firma Google rozszerzyła narzędzie make_ext4fs do utrzymywania spójnej 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 istnieje plik .map w katalogu IMAGES (na przykład IMAGES/system.map odpowiada partycji system ). Te pliki base_fs można następnie zaewidencjonować 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 zmniejszyć ogólnego rozmiaru pakietu OTA, poprawia wydajność aktualizacji OTA poprzez zmniejszenie liczby operacji we/wy. W przypadku aktualizacji Virtual A/B drastycznie zmniejsza ilość miejsca potrzebnego do zastosowania OTA.

Unikaj aktualizacji aplikacji

Oprócz minimalizowania różnic między kompilacjami możesz zmniejszyć rozmiary aktualizacji OTA, wykluczając aktualizacje aplikacji, które otrzymują aktualizacje za pośrednictwem sklepów z aplikacjami. Pakiety APK często obejmują 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żytkowników. Zanim użytkownicy otrzymają pakiet OTA, mogą już mieć zaktualizowaną aplikację lub nawet nowszą wersję, otrzymaną bezpośrednio ze sklepów z aplikacjami.