Ta strona opisuje zmiany wprowadzone w AOSP, aby zmniejszyć liczbę niepotrzebnych zmian w plikach między kompilacjami. Osoby wdrażające urządzenia, które utrzymują własne systemy kompilacji, mogą użyć tych informacji jako przewodnika aby zmniejszyć rozmiar aktualizacji bezprzewodowych.
Aktualizacje bezprzewodowe Androida czasami zawierają zmienione pliki, które nie odpowiadają zmianom w kodzie. Są to artefakty systemu kompilacji. Może się to zdarzyć, gdy ten sam kod, skompilowany w różnym czasie, z różnych katalogów lub na różnych maszynach, powoduje dużą liczbę zmienionych plików. Takie nadmiarowe pliki zwiększają rozmiar poprawki bezprzewodowej i utrudniają określenie który kod został zmieniony.
Aby zwiększyć przejrzystość zawartości aktualizacji bezprzewodowej, AOSP zawiera zmiany w systemie kompilacji, które mają na celu zmniejszenie rozmiaru poprawek bezprzewodowych. Wyeliminowano niepotrzebne zmiany w plikach między kompilacjami, a aktualizacje bezprzewodowe zawierają tylko pliki związane z poprawkami. AOSP zawiera też narzędzie do porównywania kompilacji, które odfiltrowuje typowe zmiany w plikach związane z kompilacją, aby zapewnić czystsze porównanie 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 zapobiec, w Androidzie 8.0 i nowszych wersjach wprowadzono nowe funkcje, które zmniejszają rozmiar poprawki dla każdej różnicy w plikach. Ulepszenia, które zmniejszyły rozmiar pakietów aktualizacji bezprzewodowych, obejmują:
-
Użycie ZSTD, czyli algorytmu kompresji bezstratnej ogólnego przeznaczenia, do pełnych
obrazów w aktualizacjach urządzeń innych niż A/B. ZSTD można dostosować do wyższych
współczynników kompresji, zwiększając poziom kompresji. Poziom kompresji jest ustawiany podczas generowania aktualizacji bezprzewodowej
i można go ustawić, przekazując flagę
--vabc_compression_param=zstd,$COMPRESSION_LEVEL -
Zwiększenie rozmiaru okna kompresji używanego podczas aktualizacji bezprzewodowej. Maksymalny rozmiar okna kompresji
można ustawić, dostosowując parametr kompilacji w pliku
.mkurządzenia. Ta zmienna jest ustawiona jakoPRODUCT_VIRTUAL_AB_COMPRESSION_FACTOR := 262144 - Użycie Puffin, czyli narzędzia do ponownej kompresji, które jest deterministycznym narzędziem do tworzenia poprawek dla strumieni deflate i obsługuje funkcje kompresji i różnicowania na potrzeby generowania aktualizacji bezprzewodowych A/B.
-
Zmiany w użyciu narzędzia do generowania różnic, np. sposobu używania biblioteki
bsdiffdo kompresowania poprawek. W Androidzie 9 i nowszych wersjach narzędziebsdiffwybiera algorytm kompresji, który zapewni najlepsze wyniki kompresji dla poprawki. -
Ulepszenia
update_enginespowodowały zmniejszenie zużycia pamięci podczas stosowania poprawek do aktualizacji urządzeń A/B.
W kolejnych sekcjach omówimy różne problemy, które wpływają na rozmiar aktualizacji bezprzewodowych, ich rozwiązania, oraz przykłady implementacji w AOSP.
Kolejność plików
Problem: systemy plików nie gwarantują kolejności plików, gdy prosisz o listę
plików w katalogu, chociaż w przypadku tego samego wyewidencjonowania jest ona zwykle taka sama. 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 musisz posortować
dane wyjściowe.
Rozwiązanie: gdy używasz narzędzi takich jak find i
make z funkcją symboli wieloznacznych, przed ich użyciem posortuj dane wyjściowe tych poleceń. Jeśli używasz $(wildcard) lub $(shell find) w
Android.mk plikach, posortuj je. Niektóre narzędzia, np. Java, sortują dane wejściowe, więc
przed posortowaniem plików sprawdź, czy używane narzędzie nie zrobiło tego już.
Przykłady: wiele instancji zostało naprawionych w podstawowym systemie kompilacji za pomocą
wbudowanego makra all-*-files-under, które zawiera
all-cpp-files-under (ponieważ kilka definicji było rozproszonych w innych plikach makefile).
Więcej informacji znajdziesz tutaj:
- https://android.googlesource.com/platform/build/+/4d66adfd0e6d599d8502007e4ea9aaf82e95569f
- https://android.googlesource.com/platform/build/+/379f9f9cec4fe1c66b6d60a6c19fecb81b9eb410
- https://android.googlesource.com/platform/build/+/7c3e3f8314eec2c053012dd97d2ae649ebeb5653
- https://android.googlesource.com/platform/build/+/5c64b4e81c1331cab56d8a8c201f26bb263b630c
Katalog kompilacji
Problem: zmiana katalogu, w którym są kompilowane elementy, może spowodować, że pliki binarne będą się różnić. Większość ścieżek w kompilacji Androida to ścieżki względne, więc
__FILE__ w C/C++ nie stanowi problemu. Jednak symbole do debugowania domyślnie kodują pełną
ścieżkę, a .note.gnu.build-id jest generowany na podstawie haszowania pliku binarnego przed usunięciem symboli, więc zmieni się, jeśli zmienią się symbole do debugowania.
Rozwiązanie: AOSP sprawia teraz, że ścieżki do debugowania są względne. Więcej informacji znajdziesz w CL: https://android.googlesource.com/platform/build/+/6a66a887baadc9eb3d0d60e26f748b8453e27a02.
Sygnatury czasowe
Problem: sygnatury czasowe w danych wyjściowych kompilacji powodują niepotrzebne zmiany w plikach. Może się to zdarzyć w tych miejscach:
- makra
__DATE__/__TIME__/__TIMESTAMP__w kodzie C lub C++; - sygnatury czasowe osadzone w archiwach opartych na plikach ZIP.
Rozwiązania/przykłady: aby usunąć sygnatury czasowe z danych wyjściowych kompilacji, postępuj zgodnie z instrukcjami podanymi poniżej w sekcjach __DATE__/__TIME__/__TIMESTAMP__ w C/C++. i Osadzone sygnatury czasowe w archiwach.
__DATE__/__TIME__/__TIMESTAMP__ w C/C++
Te makra zawsze generują różne dane wyjściowe w przypadku różnych kompilacji, więc nie używaj ich. Oto kilka sposobów na wyeliminowanie tych makr:
- Usuń je. Przykład znajdziesz na stronie https://android.googlesource.com/platform/system/core/+/30622bbb209db187f6851e4cf0cdaa147c2fca9f.
- Aby jednoznacznie zidentyfikować uruchomiony plik binarny, odczytaj identyfikator kompilacji z nagłówka ELF.
-
Aby dowiedzieć się, kiedy został skompilowany system operacyjny, odczytaj
ro.build.date(działa to w przypadku wszystkich kompilacji z wyjątkiem kompilacji przyrostowych, które mogą nie aktualizować tej daty). Przykład znajdziesz na stronie https://android.googlesource.com/platform/external/libchrome/+/8b7977eccc94f6b3a3896cd13b4aeacbfa1e0f84.
Osadzone sygnatury czasowe w archiwach (ZIP, JAR)
Android 7.0 rozwiązał problem osadzonych sygnatur czasowych w archiwach ZIP, dodając
-X do wszystkich zastosowań polecenia zip. Spowodowało to usunięcie z pliku ZIP identyfikatora UID/GID kompilatora i rozszerzonej sygnatury czasowej systemu Unix.
Nowe narzędzie ziptime (znajdujące się w
/platform/build/+/android17-release/tools/ziptime/) resetuje normalne sygnatury czasowe w nagłówkach ZIP. Więcej informacji znajdziesz w pliku
README.
Narzędzie signapk ustawia sygnatury czasowe dla plików APK, które mogą się różnić w zależności od
strefy czasowej serwera. Więcej informacji znajdziesz w CL
https://android.googlesource.com/platform/build/+/6c41036bcf35fe39162b50d27533f0f3bfab3028.
Narzędzie signapk ustawia sygnatury czasowe dla plików APK, które mogą się różnić w zależności od
strefy czasowej serwera. Więcej informacji znajdziesz w CL
https://android.googlesource.com/platform/build/+/6c41036bcf35fe39162b50d27533f0f3bfab3028.
Ciągi tekstowe wersji
Problem: ciągi tekstowe wersji APK często miały dołączony BUILD_NUMBER do zakodowanych na stałe wersji. Nawet jeśli w pliku APK nic się nie zmieniło, nadal będzie on inny.
Rozwiązanie: usuń numer kompilacji z ciągu tekstowego wersji APK.
Przykłady:
- https://android.googlesource.com/platform/packages/apps/Camera2/+/5e0f4cf699a4c7c95e2c38ae3babe6f20c258d27
- https://android.googlesource.com/platform/build/+/d75d893da8f97a5c7781142aaa7a16cf1dbb669c
Włączanie obliczania integralności na urządzeniu
Jeśli na urządzeniu jest włączona funkcja dm-verity , narzędzia do aktualizacji bezprzewodowych automatycznie wykrywają konfigurację integralności i włączają obliczanie integralności na urządzeniu. Dzięki temu bloki integralności mogą być obliczane na urządzeniach z Androidem, zamiast być przechowywane jako surowe bajty w pakiecie aktualizacji bezprzewodowej. Bloki integralności mogą zajmować około 16 MB w przypadku partycji o rozmiarze 2 GB.
Obliczanie integralności na urządzeniu może jednak zająć dużo czasu. W szczególności kod korekcji błędów
może zająć dużo czasu. Na urządzeniach Pixel trwa to zwykle do 10
minut. Na urządzeniach niższej klasy może to potrwać dłużej. Jeśli chcesz wyłączyć obliczanie integralnoś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 bezprzewodowej. Ta flaga wyłącza obliczanie integralności na urządzeniu podczas aktualizacji bezprzewodowych.
Skraca to czas instalacji aktualizacji bezprzewodowej, ale zwiększa rozmiar pakietu aktualizacji bezprzewodowej. Jeśli na urządzeniu nie jest włączona funkcja dm-verity, przekazanie tej flagi nie ma żadnego efektu.
Spójne narzędzia do kompilacji
Problem: narzędzia, które generują zainstalowane pliki, muszą być spójne (dane wejściowe powinny zawsze generować te same dane wyjściowe).
Rozwiązania/przykłady: wymagane były zmiany w tych narzędziach do kompilacji:
- Narzędzie do tworzenia pliku NOTICE. Narzędzie do tworzenia pliku NOTICE zostało zmienione, aby tworzyć powtarzalne kolekcje NOTICE. Więcej informacji znajdziesz w CL: https://android.googlesource.com/platform/build/+/8ae4984c2c8009e7a08e2a76b1762c2837ad4f64.
- Java Android Compiler Kit (Jack). Łańcuch narzędzi Jack wymagał aktualizacji, aby obsługiwać sporadyczne zmiany w kolejności generowanych konstruktorów. Do łańcucha narzędzi dodano deterministyczne metody dostępu do konstruktorów: https://android.googlesource.com/toolchain/jack/+/056a5425b3ef57935206c19ecb198a89221ca64b.
- Kompilator ART AOT (dex2oat). Plik binarny kompilatora ART otrzymał aktualizację, która dodała opcję tworzenia deterministycznego obrazu: https://android.googlesource.com/platform/art/+/ace0dc1dd5480ad458e622085e51583653853fb9.
-
Plik libpac.so (V8). Każda kompilacja tworzy inny
/system/lib/libpac.soplik, ponieważ migawka V8 zmienia się w każdej kompilacji. Rozwiązaniem było usunięcie migawki: https://android.googlesource.com/platform/external/v8/+/e537f38c36600fd0f3026adba6b3f4cbcee1fb29. - Pliki pre-dexopt (.odex) aplikacji. Pliki pre-dexopt (.odex) zawierały niezainicjowane dopełnienie w systemach 64-bitowych. Zostało to poprawione: https://android.googlesource.com/platform/art/+/34ed3afc41820c72a3c0ab9770be66b6668aa029.
Używanie narzędzia do porównywania kompilacji
W przypadkach, gdy nie można wyeliminować zmian w plikach związanych z kompilacją, AOSP zawiera
narzędzie do porównywania kompilacji,
target_files_diff.py
które służy do porównywania 2 pakietów plików. To narzędzie wykonuje rekurencyjne porównanie 2
kompilacji, z wyłączeniem typowych zmian w plikach związanych z kompilacją, takich jak:
- oczekiwane zmiany w danych wyjściowych kompilacji (np. z powodu zmiany numeru kompilacji);
- zmiany spowodowane znanymi problemami w bieżącym systemie kompilacji.
Aby użyć narzędzia do porównywania kompilacji, uruchom to polecenie:
target_files_diff.py dir1 dir2
dir1 i dir2 to katalogi główne, które zawierają wyodrębnione pliki docelowe dla każdej kompilacji.
Zachowywanie spójności alokacji bloków
W przypadku danego pliku, mimo że jego zawartość pozostaje taka sama w 2 kompilacjach, rzeczywiste bloki które zawierają dane, mogły się zmienić. W rezultacie narzędzie do aktualizacji musi wykonać niepotrzebne operacje wejścia/wyjścia aby przenieść bloki na potrzeby aktualizacji bezprzewodowej.
W przypadku aktualizacji bezprzewodowej Virtual A/B niepotrzebne operacje wejścia/wyjścia mogą znacznie zwiększyć ilość miejsca na dysku wymaganą do przechowywania migawki copy-on-write. W przypadku aktualizacji bezprzewodowej innej niż A/B przenoszenie bloków na potrzeby aktualizacji bezprzewodowej wydłuża czas aktualizacji, ponieważ operacji wejścia/wyjścia jest więcej z powodu przenoszenia bloków.
Aby rozwiązać ten problem, w Androidzie 7.0 Google rozszerzył narzędzie make_ext4fs w celu
zachowania spójności alokacji bloków w 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. Pliki mapowania bloków (np.
pliki map base_fs) możesz wyodrębnić z pliku ZIP plików docelowych poprzedniej kompilacji. Dla każdej
ext4 partycji w katalogu
IMAGES znajduje się plik .map (np. 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
Nie zmniejsza to ogólnego rozmiaru pakietu aktualizacji bezprzewodowej, ale poprawia wydajność aktualizacji bezprzewodowej , zmniejszając liczbę operacji wejścia/wyjścia. W przypadku aktualizacji Virtual A/B znacznie zmniejsza to ilość miejsca na dysku potrzebną do zastosowania aktualizacji bezprzewodowej.
Unikanie aktualizowania aplikacji
Oprócz minimalizowania różnic w kompilacji możesz zmniejszyć rozmiar aktualizacji bezprzewodowych, wykluczając aktualizacje dla aplikacji, które są aktualizowane za pomocą sklepów z aplikacjami. Pliki APK często stanowią znaczną część różnych partycji na urządzeniu. Dołączanie najnowszych wersji aplikacji, które są aktualizowane przez sklepy z aplikacjami do aktualizacji bezprzewodowej może mieć duży wpływ na rozmiar pakietów aktualizacji bezprzewodowych i przynosić niewielkie korzyści użytkownikom. Zanim użytkownicy otrzymają pakiet aktualizacji bezprzewodowej, mogą już mieć zaktualizowaną aplikację lub nawet nowszą wersję pobraną bezpośrednio ze sklepów z aplikacjami.