Wdrażanie partycji dynamicznych

Dynamiczne partycjonowanie jest implementowane za pomocą modułu dm-linear device-mapper w jądrze Linuxa. Partycja super zawiera metadane zawierające nazwy i zakresy bloków każdej partycji dynamicznej w super. Na pierwszym etapie initte metadane są analizowane i weryfikowane, a następnie tworzone są wirtualne urządzenia blokowe reprezentujące poszczególne partycje dynamiczne.

Podczas stosowania aktualizacji OTA partycje dynamiczne są automatycznie tworzone, zmieniane lub usuwane w razie potrzeby. W przypadku urządzeń A/B istnieją 2 kopie metadanych, a zmiany są stosowane tylko do kopii reprezentującej docelowy slot.

Partycje dynamiczne są implementowane w przestrzeni użytkownika, więc partycji potrzebnych bootloaderowi nie można uczynić dynamicznymi. Na przykład boot, dtbovbmeta są odczytywane przez program rozruchowy, dlatego muszą pozostać jako partycje fizyczne.

Każda partycja dynamiczna może należeć do grupy aktualizacji. Te grupy ograniczają maksymalną ilość miejsca, jaką mogą zajmować partycje w danej grupie. Na przykład pola systemvendor mogą należeć do grupy, która ogranicza łączną wielkość pól systemvendor.

Wdrażanie partycji dynamicznych na nowych urządzeniach

W tej sekcji znajdziesz szczegółowe informacje o wdrażaniu partycji dynamicznych na nowych urządzeniach z Androidem 10 lub nowszym. Aby zaktualizować istniejące urządzenia, przeczytaj artykuł Aktualizowanie urządzeń z Androidem.

Zmiany w partycji

W przypadku urządzeń z Androidem 10 utwórz partycję o nazwie super. Partycja super obsługuje wewnętrznie gniazda A/B, więc urządzenia A/B nie wymagają oddzielnych partycji super_a i super_b. Wszystkie partycje AOSP tylko do odczytu, których nie używają bootloadery, muszą być dynamiczne i usuwane z tabeli partycji GUID (GPT). Partycje dostawcy nie muszą być dynamiczne i mogą być umieszczane w GPT.

Aby oszacować rozmiar super, dodaj rozmiary partycji, które mają zostać usunięte z GPT. W przypadku urządzeń z opcją A/B należy uwzględnić rozmiar obu sekcji. Rysunek 1 przedstawia przykładową tabelę partycji przed i po przekształceniu na partycje dynamiczne.

Układ tabeli partycji
Rysunek 1. Nowy układ tabeli partycji fizycznej podczas konwertowania na partycje dynamiczne

Obsługiwane partycje dynamiczne:

  • System
  • Dostawca
  • Produkt
  • System Ext
  • ODM

W przypadku urządzeń uruchamianych z Androidem 10 opcja wiersza poleceń jądra androidboot.super_partition musi być pusta, aby polecenie syspropro.boot.super_partition było puste.

Wyrównanie partycji

Moduł device-mapper może działać mniej wydajnie, jeśli partycja super nie jest prawidłowo wyrównana. Partycja super MUSI być dopasowana do minimalnego rozmiaru żądania we/wy określonego przez warstwę bloku. Domyślnie system kompilacji (poprzez lpmake, który generuje obraz partycji super) zakłada, że wyrównanie 1 MiB jest wystarczające dla każdej partycji dynamicznej. Dostawcy powinni jednak zadbać o to, aby partycja super była prawidłowo wyrównana.

Minimalny rozmiar żądania urządzenia blokującego można określić, sprawdzając sysfs. Przykład:

# ls -l /dev/block/by-name/super
lrwxrwxrwx 1 root root 16 1970-04-05 01:41 /dev/block/by-name/super -> /dev/block/sda17
# cat /sys/block/sda/queue/minimum_io_size
786432

Wyrównanie partycji super możesz sprawdzić w podobny sposób:

# cat /sys/block/sda/sda17/alignment_offset

Odsunięcie wyrównania MUSI wynosić 0.

Zmiany konfiguracji urządzenia

Aby włączyć dynamiczne partycjonowanie, dodaj tę flagę w pozycji:device.mk:

PRODUCT_USE_DYNAMIC_PARTITIONS := true

Zmiany konfiguracji tablicy

Musisz ustawić rozmiar partycji super:

BOARD_SUPER_PARTITION_SIZE := <size-in-bytes>

Na urządzeniach A/B system kompilacji zwraca błąd, jeśli łączny rozmiar obrazów dynamicznych partycji przekracza połowę superrozmiaru partycji.

Listę partycji dynamicznych możesz skonfigurować w ten sposób: W przypadku urządzeń korzystających z grup aktualizacji podaj grupy w zmiennej BOARD_SUPER_PARTITION_GROUPS. Każda nazwa grupy ma wtedy zmienne BOARD_group_SIZEBOARD_group_PARTITION_LIST. W przypadku urządzeń A/B maksymalny rozmiar grupy powinien obejmować tylko 1 slot, ponieważ nazwy grup są wewnętrznie dodawane do sufiksów slotów.

Oto przykład urządzenia, które umieszcza wszystkie partycje w grupie o nazwie example_dynamic_partitions:

BOARD_SUPER_PARTITION_GROUPS := example_dynamic_partitions
BOARD_EXAMPLE_DYNAMIC_PARTITIONS_SIZE := 6442450944
BOARD_EXAMPLE_DYNAMIC_PARTITIONS_PARTITION_LIST := system vendor product

Oto przykład urządzenia, na którym usługi systemowe i usługi związane z produktami są umieszczane w group_foo, a usługi vendor, productodmgroup_bar:

BOARD_SUPER_PARTITION_GROUPS := group_foo group_bar
BOARD_GROUP_FOO_SIZE := 4831838208
BOARD_GROUP_FOO_PARTITION_LIST := system product_services
BOARD_GROUP_BAR_SIZE := 1610612736
BOARD_GROUP_BAR_PARTITION_LIST := vendor product odm
  • W przypadku urządzeń z testem dynamicznym A/B suma maksymalnych rozmiarów wszystkich grup nie może przekroczyć:
    BOARD_SUPER_PARTITION_SIZE – overhead
    Zobacz Wdrażanie testu dynamicznego A/B.
  • W przypadku urządzeń z testem A/B suma maksymalnych rozmiarów wszystkich grup musi wynosić:
    BOARD_SUPER_PARTITION_SIZE / 2 – overhead
  • W przypadku urządzeń innych niż A/B i urządzeń z dodatkiem funkcji A/B suma maksymalnych rozmiarów wszystkich grup musi wynosić:
    BOARD_SUPER_PARTITION_SIZE – overhead
  • W momencie kompilacji suma rozmiarów obrazów każdej partycji w grupie aktualizacji nie może przekraczać maksymalnego rozmiaru grupy.
  • Nakład jest wymagany w obliczeniach, aby uwzględnić metadane, wyrównania itp. Rozsądny narzut to 4 MiB, ale w razie potrzeby możesz wybrać większy narzut.

Rozmiar partycji dynamicznych

Przed wprowadzeniem partycji dynamicznych rozmiary partycji były zawyżone, aby zapewnić wystarczającą ilość miejsca na przyszłe aktualizacje. Rzeczywisty rozmiar został przyjęty jako taki, jaki jest, a większość partycji tylko do odczytu miała pewną ilość wolnego miejsca w systemie plików. W przypadku partycji dynamicznych to wolne miejsce jest nieużyteczne i może być wykorzystane do zwiększenia partycji podczas aktualizacji OTA. Ważne jest, aby partycje nie marnowały miejsca i były przydzielone do minimalnego możliwego rozmiaru.

W przypadku obrazów ext4 tylko do odczytu system kompilacji automatycznie przydziela minimalny rozmiar, jeśli nie jest określony rozmiar partycji zaszyfrowanej. System kompilacji dopasowuje obraz tak, aby system plików miał jak najmniej niewykorzystanego miejsca. Dzięki temu urządzenie nie będzie marnować miejsca, które można wykorzystać na aktualizacje OTA.

Dodatkowo obrazy ext4 można dodatkowo skompresować, włączając deduplikację na poziomie bloku. Aby to włączyć, użyj tej konfiguracji:

BOARD_EXT4_SHARE_DUP_BLOCKS := true

Jeśli automatyczne przydzielanie minimalnego rozmiaru partycji jest niepożądane, możesz kontrolować rozmiar partycji na 2 sposoby. Możesz określić minimalną ilość wolnego miejsca za pomocą opcji BOARD_partitionIMAGE_PARTITION_RESERVED_SIZE lub użyć opcji BOARD_partitionIMAGE_PARTITION_SIZE, aby wymusić określony rozmiar partycji dynamicznej. Żadna z nich nie jest zalecana, jeśli nie jest niezbędna.

Przykład:

BOARD_PRODUCTIMAGE_PARTITION_RESERVED_SIZE := 52428800

Wymusza to, aby system plików w product.img miał 50 MiB niewykorzystanego miejsca.

Zmiany w systemie działającym jako root

Urządzenia z Androidem 10 nie mogą używać systemu jako roota.

Urządzenia z partycjami dynamicznymi (czy to z partycjami dynamicznymi w wersji startowej, czy z partycjami dynamicznymi w wersji wstecznej) nie mogą używać systemu jako roota. Rdzeń Linuksa nie może interpretować partycji super, więc nie może zamontować system. system jest teraz montowany przez pierwszy etap init, który znajduje się w pamięci RAM.

Nie ustawiaj BOARD_BUILD_SYSTEM_ROOT_IMAGE. W Androidzie 10 flaga BOARD_BUILD_SYSTEM_ROOT_IMAGE służy tylko do rozróżniania, czy system jest montowany przez jądro czy przez pierwszy etap init w ramdisku.

Ustawienie wartości BOARD_BUILD_SYSTEM_ROOT_IMAGE na true powoduje błąd kompilacji, gdy wartość PRODUCT_USE_DYNAMIC_PARTITIONS jest również równa true.

Gdy parametr BOARD_USES_RECOVERY_AS_BOOT ma wartość Prawda, obraz przywracania jest tworzony jako boot.img, zawierający pamięć RAM odzyskiwania. Wcześniej bootloader używał parametru wiersza poleceń skip_initramfs jądra do określenia trybu rozruchu. W przypadku urządzeń z Androidem 10 bootloader NIE MOŻE przekazywać parametru skip_initramfs do wiersza poleceń jądra. Zamiast tego bootloader powinien przekazać wartość androidboot.force_normal_boot=1, aby pominąć odzyskiwanie i uruchomić normalnego Androida. Urządzenia uruchamiane z Androidem 12 lub nowszym muszą używać bootconfig do przekazywania wartości androidboot.force_normal_boot=1.

Zmiany konfiguracji AVB

Jeśli używasz weryfikacji podczas uruchamiania w Androidzie 2.0, a urządzenie nie używa łańcuchowych opisów partycji, nie musisz wprowadzać żadnych zmian. Jeśli jednak używasz połączonych partycji, a jedna z zweryfikowanych partycji jest dynamiczna, konieczne są zmiany.

Oto przykładowa konfiguracja urządzenia, które łączy vbmeta w przypadku partycji systemvendor.

BOARD_AVB_SYSTEM_KEY_PATH := external/avb/test/data/testkey_rsa2048.pem
BOARD_AVB_SYSTEM_ALGORITHM := SHA256_RSA2048
BOARD_AVB_SYSTEM_ROLLBACK_INDEX := $(PLATFORM_SECURITY_PATCH_TIMESTAMP)
BOARD_AVB_SYSTEM_ROLLBACK_INDEX_LOCATION := 1

BOARD_AVB_VENDOR_KEY_PATH := external/avb/test/data/testkey_rsa2048.pem
BOARD_AVB_VENDOR_ALGORITHM := SHA256_RSA2048
BOARD_AVB_VENDOR_ROLLBACK_INDEX := $(PLATFORM_SECURITY_PATCH_TIMESTAMP)
BOARD_AVB_VENDOR_ROLLBACK_INDEX_LOCATION := 1

W ramach tej konfiguracji bootloader oczekuje, że na końcu partycji systemvendor znajdzie stopkę VBmeta. Ponieważ te partycje nie są już widoczne dla bootloadera (znajdują się w super), konieczne są 2 zmiany.

  • Dodaj partycje vbmeta_systemvbmeta_vendor do tabeli partycji urządzenia. W przypadku urządzeń A/B dodaj: vbmeta_system_a, vbmeta_system_b, vbmeta_vendor_avbmeta_vendor_b. Jeśli dodajesz jedną lub więcej takich partycji, powinny one mieć taki sam rozmiar jak partycja vbmeta.
  • Zmień nazwy flag konfiguracji, dodając VBMETA_ i określ, do których partycji ma się odnosić łańcuch:
    BOARD_AVB_VBMETA_SYSTEM := system
    BOARD_AVB_VBMETA_SYSTEM_KEY_PATH := external/avb/test/data/testkey_rsa2048.pem
    BOARD_AVB_VBMETA_SYSTEM_ALGORITHM := SHA256_RSA2048
    BOARD_AVB_VBMETA_SYSTEM_ROLLBACK_INDEX := $(PLATFORM_SECURITY_PATCH_TIMESTAMP)
    BOARD_AVB_VBMETA_SYSTEM_ROLLBACK_INDEX_LOCATION := 1
    
    BOARD_AVB_VBMETA_VENDOR := vendor
    BOARD_AVB_VBMETA_VENDOR_KEY_PATH := external/avb/test/data/testkey_rsa2048.pem
    BOARD_AVB_VBMETA_VENDOR_ALGORITHM := SHA256_RSA2048
    BOARD_AVB_VBMETA_VENDOR_ROLLBACK_INDEX := $(PLATFORM_SECURITY_PATCH_TIMESTAMP)
    BOARD_AVB_VBMETA_VENDOR_ROLLBACK_INDEX_LOCATION := 1

Urządzenie może używać jednej, obu lub żadnej z tych partycji. Zmiany są potrzebne tylko wtedy, gdy łańcuch jest tworzony do partycji logicznej.

Zmiany w programie rozruchowym AVB

Jeśli bootloader zawiera wbudowaną bibliotekę libavb, dołącz te poprawki:

Jeśli używasz połączonych partycji, dodaj dodatkową łatkę:

  • 49936b4c0109411fdd38bd4ba3a32a01c40439a9 — „libavb: obsługa blobów vbmeta na początku partycji”.

Zmiany w wierszu poleceń jądra

Do wiersza poleceń jądra należy dodać nowy parametr androidboot.boot_devices. init używa tego do włączania /dev/block/by-name linków symbolicznych. Powinien to być element ścieżki urządzenia do docelowego symbolicznego linku nazwy utworzonego przez ueventd, czyli /dev/block/platform/device-path/by-name/partition-name. Urządzenia uruchamiane z Androidem 12 lub nowszym muszą używać pliku bootconfig, aby przekazać wartość androidboot.boot_devices do init.

Jeśli na przykład symboliczny link do superpartycji oparty na nazwie to /dev/block/platform/soc/100000.ufshc/by-name/super, możesz dodać parametr wiersza poleceń w pliku BoardConfig.mk w ten sposób:

BOARD_KERNEL_CMDLINE += androidboot.boot_devices=soc/100000.ufshc
Parametr bootconfig możesz dodać w pliku BoardConfig.mk w ten sposób:
BOARD_BOOTCONFIG += androidboot.boot_devices=soc/100000.ufshc

zmiany w pliku fstab.

Struktura drzewa urządzenia i nakładki struktury urządzenia nie mogą zawierać wpisów fstab. Użyj pliku fstab, który będzie częścią dysku RAM.

W przypadku partycji logicznych należy wprowadzić zmiany w pliku fstab:

  • Pole fs_mgr flags musi zawierać flagę logical oraz flagę first_stage_mount, wprowadzoną w Androidzie 10, która wskazuje, że partycja ma zostać zamontowana na pierwszym etapie.
  • Partycja może określać avb=vbmeta partition name jako flagę fs_mgr, a następnie partycja vbmeta jest inicjowana przez pierwszy etap init, zanim nastąpi próba zamontowania jakichkolwiek urządzeń.
  • Pole dev musi zawierać nazwę partycji.

Podane niżej wpisy fstab ustawiają system, producenta i produkt jako partycje logiczne zgodnie z podanymi wyżej regułami.

#<dev>  <mnt_point> <type>  <mnt_flags options> <fs_mgr_flags>
system   /system     ext4    ro,barrier=1        wait,slotselect,avb=vbmeta,logical,first_stage_mount
vendor   /vendor     ext4    ro,barrier=1        wait,slotselect,avb,logical,first_stage_mount
product  /product    ext4    ro,barrier=1        wait,slotselect,avb,logical,first_stage_mount

Skopiuj plik fstab do pamięci RAM pierwszego etapu.

Zmiany w SELinux

Urządzenie blokujące super partycję musi być oznaczone etykietą super_block_device. Jeśli na przykład symboliczny link do super partycji o nazwie to/dev/block/platform/soc/100000.ufshc/by-name/super, dodaj ten wiersz do pliku file_contexts:

/dev/block/platform/soc/10000\.ufshc/by-name/super   u:object_r:super_block_device:s0

fastbootd

Bootloader (lub dowolne narzędzie do flashowania niebędące narzędziem dla użytkownika) nie rozumie partycji dynamicznych, więc nie może ich flashować. Aby rozwiązać ten problem, urządzenia muszą używać implementacji protokołu fastboot w przestrzeni użytkownika, zwanej fastbootd.

Więcej informacji o wdrażaniu fastbootd znajdziesz w artykule Przenoszenie Fastboot do przestrzeni użytkownika.

adb remount

W przypadku deweloperów korzystających z kompilacji eng lub userdebug adb remountjest niezwykle przydatne do szybkiego iterowania. Dynamiczne partycje stanowią problem dla adb remount, ponieważ w każdym systemie plików nie ma już wolnego miejsca. Aby rozwiązać ten problem, urządzenia mogą włączyć overlayfs. Dopóki w superpartycji jest wolne miejsce, adb remount automatycznie tworzy tymczasową partycję dynamiczną i używa overlayfs do zapisu. Tymczasowa partycja ma nazwę scratch, więc nie używaj tej nazwy dla innych partycji.

Więcej informacji o włączaniu overlayfs znajdziesz w README overlayfs w AOSP.

Aktualizowanie urządzeń z Androidem

Jeśli zaktualizujesz urządzenie do Androida 10 i chcesz uwzględnić obsługę dynamicznych partycji w aktualizacji OTA, nie musisz zmieniać wbudowanej tabeli partycji. Wymaga dodatkowej konfiguracji.

Zmiany konfiguracji urządzenia

Aby dostosować dynamiczne partycjonowanie, dodaj te flagi w pliku device.mk:

PRODUCT_USE_DYNAMIC_PARTITIONS := true
PRODUCT_RETROFIT_DYNAMIC_PARTITIONS := true

Zmiany konfiguracji tablicy

Musisz ustawić te zmienne planszy:

  • Ustaw BOARD_SUPER_PARTITION_BLOCK_DEVICES na listę urządzeń blokowych używanych do przechowywania zakresów partycji dynamicznych. Lista nazw istniejących partycji fizycznych na urządzeniu.
  • Ustaw BOARD_SUPER_PARTITION_partition_DEVICE_SIZE na rozmiary poszczególnych urządzeń blokujących w elementach BOARD_SUPER_PARTITION_BLOCK_DEVICES. Lista rozmiarów istniejących partycji fizycznych na urządzeniu. Zwykle jest toBOARD_partitionIMAGE_PARTITION_SIZE w przypadku istniejących konfiguracji tablicy.
  • Odznacz istniejące BOARD_partitionIMAGE_PARTITION_SIZE na wszystkich partycjach w BOARD_SUPER_PARTITION_BLOCK_DEVICES.
  • Ustaw wartość BOARD_SUPER_PARTITION_SIZE na sumę wartości w kolumnie BOARD_SUPER_PARTITION_partition_DEVICE_SIZE.
  • Ustaw BOARD_SUPER_PARTITION_METADATA_DEVICE na urządzenie blokowe, na którym przechowywane są metadane dynamicznej partycji. Musi to być wartość ze zbioru BOARD_SUPER_PARTITION_BLOCK_DEVICES. Zwykle jest to system.
  • Ustaw odpowiednio BOARD_SUPER_PARTITION_GROUPS, BOARD_group_SIZE i BOARD_group_PARTITION_LIST. Więcej informacji znajdziesz w artykule Zmiany w konfiguracji tablicy na nowych urządzeniach.

Jeśli na przykład urządzenie ma już partycje systemową i partycję producenta, a chcesz przekonwertować je na partycje dynamiczne i dodać nową partycję produktu podczas aktualizacji, ustaw tę konfigurację płyty głównej:

BOARD_SUPER_PARTITION_BLOCK_DEVICES := system vendor
BOARD_SUPER_PARTITION_METADATA_DEVICE := system

# Rename BOARD_SYSTEMIMAGE_PARTITION_SIZE to BOARD_SUPER_PARTITION_SYSTEM_DEVICE_SIZE.
BOARD_SUPER_PARTITION_SYSTEM_DEVICE_SIZE := <size-in-bytes>

# Rename BOARD_VENDORIMAGE_PARTITION_SIZE to BOARD_SUPER_PARTITION_VENDOR_DEVICE_SIZE
BOARD_SUPER_PARTITION_VENDOR_DEVICE_SIZE := <size-in-bytes>

# This is BOARD_SUPER_PARTITION_SYSTEM_DEVICE_SIZE + BOARD_SUPER_PARTITION_VENDOR_DEVICE_SIZE
BOARD_SUPER_PARTITION_SIZE := <size-in-bytes>

# Configuration for dynamic partitions. For example:
BOARD_SUPER_PARTITION_GROUPS := group_foo
BOARD_GROUP_FOO_SIZE := <size-in-bytes>
BOARD_GROUP_FOO_PARTITION_LIST := system vendor product

Zmiany w SELinux

Urządzenia w superpartycji muszą być oznaczone atrybutem super_block_device_type. Jeśli na przykład urządzenie ma już partycje system i vendor, które chcesz używać jako urządzenia blokowe do przechowywania rozszerzeń partycji dynamicznych, a ich symboliczne linki są oznaczone jako system_block_device:

/dev/block/platform/soc/10000\.ufshc/by-name/system   u:object_r:system_block_device:s0
/dev/block/platform/soc/10000\.ufshc/by-name/vendor   u:object_r:system_block_device:s0

Następnie dodaj do pliku device.te ten wiersz:

typeattribute system_block_device super_block_device_type;

Inne konfiguracje znajdziesz w artykule Wdrażanie partycji dynamicznych na nowych urządzeniach.

Więcej informacji o aktualizacjach wstecznych znajdziesz w artykule OTA dla urządzeń A/B bez partycji dynamicznych.

Obrazy fabryczne

W przypadku urządzenia uruchamianego z obsługą partycji dynamicznych nie należy używać fastboot w przestrzeni użytkownika do flashowania obrazów fabrycznych, ponieważ uruchamianie w przestrzeni użytkownika jest wolniejsze niż inne metody flashowania.

Aby rozwiązać ten problem, make dist tworzy teraz dodatkowy obraz super.img, który można zainstalować bezpośrednio na superpartycji. Automatycznie łączy zawartość partycji logicznych, co oznacza, że zawiera system.img, vendor.img itd., oprócz metadanych partycji super. Obraz można wgrać bezpośrednio na partycję super bez użycia dodatkowych narzędzi lub fastbootd. Po kompilacji super.img jest umieszczany w ${ANDROID_PRODUCT_OUT}.

W przypadku urządzeń A/B, które korzystają z dynamicznych partycji, super.img zawiera obrazy w miejscu A. Po zaflashowaniu superobrazu bezpośrednio oznaczysz gniazdo A jako gniazdo startowe, zanim uruchomisz ponownie urządzenie.

W przypadku urządzeń z dodatkowymi modułami make dist tworzy zestaw obrazów super_*.img, które można wgrać bezpośrednio na odpowiednie fizyczne partycje. Na przykład make dist tworzy super_system.img i super_vendor.img, gdy BOARD_SUPER_PARTITION_BLOCK_DEVICES jest dostawcą systemu. Obrazy te są umieszczane w folderze OTA w folderze target_files.zip.

Dostosowanie pamięci urządzenia w ramach usługi mapowania urządzeń

Dynamiczne partycjonowanie obsługuje pewną liczbę niedeterministycznych obiektów device-mapper. Nie wszystkie z nich mogą zostać utworzone zgodnie z oczekiwaniami, dlatego musisz śledzić wszystkie zamontowane urządzenia i aktualizować właściwości Androida wszystkich powiązanych partycji z podłączonymi urządzeniami pamięci masowej.

Mechanizm w komponencie init śledzi punkty zamontowania i asymetrycznie aktualizuje właściwości Androida. Nie ma gwarancji, że proces ten zakończy się w określonym czasie, dlatego musisz zapewnić wystarczająco dużo czasu na reakcję wszystkich on property wyzwalaczy. Właściwości to dev.mnt.blk.<partition>, gdzie <partition> to na przykład root, system, data lub vendor. Każda usługa jest powiązana z nazwą podstawowego urządzenia pamięci masowej, jak w tych przykładach:

taimen:/ % getprop | grep dev.mnt.blk
[dev.mnt.blk.data]: [sda]
[dev.mnt.blk.firmware]: [sde]
[dev.mnt.blk.metadata]: [sde]
[dev.mnt.blk.persist]: [sda]
[dev.mnt.blk.root]: [dm-0]
[dev.mnt.blk.vendor]: [dm-1]

blueline:/ $ getprop | grep dev.mnt.blk
[dev.mnt.blk.data]: [dm-4]
[dev.mnt.blk.metadata]: [sda]
[dev.mnt.blk.mnt.scratch]: [sda]
[dev.mnt.blk.mnt.vendor.persist]: [sdf]
[dev.mnt.blk.product]: [dm-2]
[dev.mnt.blk.root]: [dm-0]
[dev.mnt.blk.system_ext]: [dm-3]
[dev.mnt.blk.vendor]: [dm-1]
[dev.mnt.blk.vendor.firmware_mnt]: [sda]

Język init.rc umożliwia rozszerzenie właściwości Androida w ramach reguł, a urządzenia do przechowywania danych mogą być dostosowywane przez platformę w miarę potrzeby za pomocą takich poleceń:

write /sys/block/${dev.mnt.blk.root}/queue/read_ahead_kb 128
write /sys/block/${dev.mnt.blk.data}/queue/read_ahead_kb 128

Gdy rozpocznie się przetwarzanie poleceń na drugim etapie init, element epoll loop stanie się aktywny, a wartości zaczną się aktualizować. Ponieważ jednak wyzwalacze w usłudze są aktywne dopiero pod koniec init, nie można ich używać na początkowych etapach uruchamiania, aby obsługiwać root, system ani vendor. Warto ustawić domyślną wartość read_ahead_kb w jądrze, dopóki skrypty init.rc nie zastąpią wartości early-fs (gdy uruchamiają się różne demony i usługi). Dlatego Google zaleca korzystanie z funkcji on property w połączeniu z usługą sterowaną przez init.rc, np. sys.read_ahead_kb, aby zarządzać czasem wykonywania operacji i zapobiegać warunkom rywalizacji, jak w tych przykładach:

on property:dev.mnt.blk.root=* && property:sys.read_ahead_kb=*
    write /sys/block/${dev.mnt.blk.root}/queue/read_ahead_kb ${sys.read_ahead_kb:-2048}

on property:dev.mnt.blk.system=* && property:sys.read_ahead_kb=*
    write /sys/block/${dev.mnt.blk.system}/queue/read_ahead_kb ${sys.read_ahead_kb:-2048}

on property:dev.mnt.blk.vendor=* && property:sys.read_ahead_kb=*
    write /sys/block/${dev.mnt.blk.vendor}/queue/read_ahead_kb ${sys.read_ahead_kb:-2048}

on property:dev.mnt.blk.product=* && property:sys.read_ahead_kb=*
    write /sys/block/${dev.mnt.blk.system_ext}/queue/read_ahead_kb ${sys.read_ahead_kb:-2048}

on property:dev.mnt.blk.oem=* && property:sys.read_ahead_kb=*
    write /sys/block/${dev.mnt.blk.oem}/queue/read_ahead_kb ${sys.read_ahead_kb:-2048}

on property:dev.mnt.blk.data=* && property:sys.read_ahead_kb=*
    write /sys/block/${dev.mnt.blk.data}/queue/read_ahead_kb ${sys.read_ahead_kb:-2048}

on early-fs:
    setprop sys.read_ahead_kb ${ro.read_ahead_kb.boot:-2048}

on property:sys.boot_completed=1
   setprop sys.read_ahead_kb ${ro.read_ahead_kb.bootcomplete:-128}