W tym dokumencie opisujemy projekt rozwiązania do buforowania plików APK, które umożliwia szybkie instalowanie wstępnie załadowanych aplikacji na urządzeniu obsługującym partycje A/B.
Producenci urządzeń mogą umieszczać w pamięci podręcznej APK popularne aplikacje przechowywane na prawie pustej partycji B na nowych urządzeniach z partycjami A/B bez wpływu na przestrzeń danych przeznaczoną dla użytkownika. Dzięki pamięci podręcznej plików APK na urządzeniu nowe urządzenia lub urządzenia, które zostały niedawno przywrócone do ustawień fabrycznych, są gotowe do użycia niemal natychmiast, bez konieczności pobierania plików APK z Google Play.
Przykłady zastosowań
- przechowywanie preinstalowanych aplikacji na partycji B w celu szybszego konfigurowania;
- przechowywanie popularnych aplikacji na partycji B w celu szybszego przywracania;
Wymagania wstępne
Aby korzystać z tej funkcji, urządzenie musi mieć:
- Zainstalowana wersja Androida 8.1 (O MR1)
- Wdrożona partycja A/B
Wstępnie załadowane treści można kopiować tylko podczas pierwszego uruchamiania. Dzieje się tak, ponieważ na urządzeniach obsługujących aktualizacje systemu A/B partycja B nie przechowuje plików obrazu systemu, ale zamiast tego wstępnie załadowane treści, takie jak zasoby demonstracyjne, pliki OAT i pamięć podręczna APK. Po skopiowaniu zasobów na partycję /data (dzieje się to podczas pierwszego uruchomienia) partycja B będzie używana przez aktualizacje bezprzewodowe (OTA) do pobierania zaktualizowanych wersji obrazu systemu.
Dlatego pamięć podręczna APK nie może być aktualizowana za pomocą OTA; może być wstępnie wczytana tylko w fabryce. Przywracanie ustawień fabrycznych ma wpływ tylko na partycję /data. Do czasu pobrania obrazu OTA system B nadal ma wstępnie załadowane treści. Po przywróceniu do ustawień fabrycznych system ponownie przejdzie przez pierwszy proces uruchamiania. Oznacza to, że buforowanie APK jest niedostępne, jeśli obraz OTA został pobrany na partycję B, a następnie urządzenie zostało zresetowane do ustawień fabrycznych.
Implementacja
Podejście 1. Treści na partycji system_other
Porada: w przypadku przywrócenia ustawień fabrycznych nie tracisz zainstalowanych wcześniej treści. Po ponownym uruchomieniu urządzenia zostaną one skopiowane z partycji B.
Cons: wymaga miejsca na partycji B. Uruchamianie po przywróceniu ustawień fabrycznych wymaga dodatkowego czasu na skopiowanie wstępnie załadowanych treści.
Aby dane wstępne zostały skopiowane podczas pierwszego uruchomienia, system wywołuje skrypt w /system/bin/preloads_copy.sh
. Skrypt jest wywoływany z jednym argumentem (ścieżką do punktu zamontowania tylko do odczytu dla partycji system_b
):
Aby wdrożyć tę funkcję, wprowadź te zmiany na urządzeniu. Oto przykład z Marlin:
- Dodaj skrypt, który wykonuje kopiowanie, do pliku
device-common.mk
(w tym przypadkudevice/google/marlin/device-common.mk
), w ten sposób: Przykładowy skrypt źródłowy znajdziesz tutaj: device/google/marlin/preloads_copy.sh# Script that copies preloads directory from system_other to data partition PRODUCT_COPY_FILES += \ device/google/marlin/preloads_copy.sh:system/bin/preloads_copy.sh
- Zmień plik
init.common.rc
, aby utworzyć potrzebny katalog/data/preloads
i podkatalogi: Przykładowy plik źródłowymkdir /data/preloads 0775 system system
mkdir /data/preloads/media 0775 system system
mkdir /data/preloads/demo 0775 system system
init
znajdziesz w folderze: device/google/marlin/init.common.rc - Zdefiniuj nową domenę SELinux w pliku
preloads_copy.te
: Przykładowy plik domeny SELinux znajdziesz w folderze /device/google/marlin/+/main/sepolicy/preloads_copy.te.type preloads_copy, domain, coredomain; type preloads_copy_exec, exec_type, vendor_file_type, file_type; init_daemon_domain(preloads_copy) allow preloads_copy shell_exec:file rx_file_perms; allow preloads_copy toolbox_exec:file rx_file_perms; allow preloads_copy preloads_data_file:dir create_dir_perms; allow preloads_copy preloads_data_file:file create_file_perms; allow preloads_copy preloads_media_file:dir create_dir_perms; allow preloads_copy preloads_media_file:file create_file_perms; # Allow to copy from /postinstall allow preloads_copy system_file:dir r_dir_perms;
- Zarejestruj domenę w nowym pliku
:/sepolicy/file_contexts Przykładowy plik kontekstów SELinux znajdziesz w folderze: device/google/marlin/sepolicy/preloads_copy.te/system/bin/preloads_copy\.sh u:object_r:preloads_copy_exec:s0
- Podczas kompilacji katalog z zainstalowanymi treściami musi zostać skopiowany na partycję
system_other
: To przykład zmiany w Makefile, która umożliwia kopiowanie zasobów pamięci podręcznej APK z repozytorium Git dostawcy (w naszym przypadku było to vendor/google_devices/marlin/preloads) do lokalizacji na partycji system_other, która zostanie później skopiowana do katalogu /data/preloads podczas pierwszego uruchamiania urządzenia. Ten skrypt jest uruchamiany w czasie kompilacji w celu przygotowania obrazu system_other. Załadowane treści powinny być dostępne w folderze vendor/google_devices/marlin/preloads. OEM może dowolnie wybrać nazwę lub ścieżkę repozytorium.# Copy contents of preloads directory to system_other partition PRODUCT_COPY_FILES += \ $(call find-copy-subdir-files,*,vendor/google_devices/marlin/preloads,system_other/preloads)
- Pamięć podręczna APK znajduje się w folderze
/data/preloads/file_cache
i ma taki układ: To jest ostateczna struktura katalogów na urządzeniach. Producenci OEM mogą wybrać dowolne podejście do implementacji, o ile końcowa struktura pliku odzwierciedla strukturę opisaną powyżej./data/preloads/file_cache/ app.package.name.1/ file1 fileN app.package.name.N/
Sposób 2. Treści dotyczące danych użytkownika (flash image)
To alternatywne podejście zakłada, że wstępnie załadowane treści są już zawarte w katalogu /data/preloads
na partycji /data
.
Pro: działa od razu po zainstalowaniu – nie trzeba wprowadzać żadnych zmian na urządzeniu, aby skopiować pliki przy pierwszym uruchomieniu. Treści znajdują się już w partycji /data
.
Wady: po przywróceniu ustawień fabrycznych utracisz zapisane wcześniej treści. Chociaż może to być akceptowalne w niektórych przypadkach, nie zawsze sprawdza się w przypadku producentów OEM, którzy resetują urządzenia do ustawień fabrycznych po przeprowadzeniu kontroli jakości.
Do obiektu android.content.Context
dodano nową metodę @SystemApi: getPreloadsFileCache()
. Zwraca ścieżkę bezwzględną do katalogu aplikacji w wstępnie załadowanej pamięci podręcznej.
Dodano nową metodę IPackageManager.deletePreloadsFileCache
, która umożliwia usunięcie katalogu z zawartością do pobrania, aby odzyskać całą przestrzeń. Metoda może być wywoływana tylko przez aplikacje z SYSTEM_UID, np. serwer systemowy lub Ustawienia.
Przygotowanie aplikacji
Dostęp do katalogu pamięci podręcznej z zawartością do wstępnego załadowania mają tylko aplikacje z przywilejami. Aby uzyskać dostęp, aplikacje muszą być zainstalowane w katalogu /system/priv-app
.
Weryfikacja
- Po pierwszym uruchomieniu na urządzeniu powinny znajdować się dane w katalogu
/data/preloads/file_cache
. - Jeśli na urządzeniu zabraknie miejsca, zawartość katalogu
file_cache/
musi zostać usunięta.
Użyj przykładowej aplikacji ApkCacheTest do testowania pamięci podręcznej pliku APK.
- Skompiluj aplikację, uruchamiając to polecenie w katalogu głównym:
make ApkCacheTest
- Zainstaluj aplikację jako aplikację uprzywilejowaną (pamiętaj, że tylko aplikacje uprzywilejowane mają dostęp do pamięci podręcznej APK).
Wymaga to urządzenia z rootem:
adb root && adb remount
adb shell mkdir /system/priv-app/ApkCacheTest
adb push $ANDROID_PRODUCT_OUT/data/app/ApkCacheTest/ApkCacheTest.apk /system/priv-app/ApkCacheTest/
adb shell stop && adb shell start
- Symulowanie katalogu pamięci podręcznej plików i jego zawartości w razie potrzeby (wymaga to też uprawnień roota):
adb shell mkdir -p /data/preloads/file_cache/com.android.apkcachetest
adb shell restorecon -r /data/preloads
adb shell "echo "Test File" > /data/preloads/file_cache/com.android.apkcachetest/test.txt"
- Przetestuj aplikację. Po zainstalowaniu aplikacji i utworzeniu testowego katalogu
file_cache
otwórz aplikację ApkCacheTest. Powinna ona wyświetlić 1 pliktest.txt
i jego zawartość. Na zrzucie ekranu widać, jak te wyniki wyglądają w interfejsie.
Rysunek 1. Wyniki ApkCacheTest.