Dynamiczne aktualizacje systemu

Dynamiczne aktualizacje systemu (DSU) umożliwiają utworzenie obrazu systemu Android, który użytkownicy mogą pobrać z internetu i wypróbować bez ryzyka uszkodzenia bieżącego obrazu systemu. Z tego dokumentu dowiesz się, jak obsługiwać DSU.

Wymagania dotyczące jądra

Wymagania dotyczące jądra znajdziesz w sekcji Wdrażanie partycji dynamicznych.

DSU korzysta też z funkcji jądra device-mapper-verity (dm-verity), aby weryfikować obraz systemu Androida. Musisz więc włączyć te konfiguracje jądra:

  • CONFIG_DM_VERITY=y
  • CONFIG_DM_VERITY_FEC=y

Wymagania dotyczące partycji

Od Androida 11 DSU wymaga, aby partycja /data używała systemu plików F2FS lub ext4. F2FS zapewnia lepszą wydajność i jest zalecany, ale różnica powinna być nieznaczna.

Oto kilka przykładów czasu trwania dynamicznej aktualizacji systemu na urządzeniu Pixel:

  • Korzystanie z F2FS:
    • 109 s, 8 G użytkownika, 867 M systemu, typ systemu plików: F2FS: encryption=aes-256-xts:aes-256-cts
    • 104 s, 8 G użytkownika, 867 M system, typ systemu plików: F2FS: encryption=ice
  • Korzystanie z ext4:
    • 135 s, 8 GB użytkownika, 867 MB systemu, typ systemu plików: ext4: encryption=aes-256-xts:aes-256-cts

Jeśli na Twojej platformie trwa to znacznie dłużej, sprawdź, czy flaga montowania zawiera flagę, która powoduje zapis „sync”, lub możesz jawnie określić flagę „async”, aby uzyskać lepszą wydajność.

Partycja metadata (o rozmiarze co najmniej 16 MB) jest wymagana do przechowywania danych związanych z zainstalowanymi obrazami. Musi być zamontowany podczas montażu w pierwszej fazie.

Partycja userdata musi używać systemu plików F2FS lub ext4. Jeśli używasz systemu F2FS, uwzględnij wszystkie poprawki związane z tym systemem dostępne w wspólnym jądrze Androida.

DSU został opracowany i przetestowany na jądrze/wspólnej wersji 4.9. W przypadku tej funkcji zalecamy używanie jądra w wersji 4.9 lub nowszej.

Zachowanie interfejsu HAL dostawcy

Warstwa HAL Weaver

Warstwa HAL Weaver udostępnia stałą liczbę miejsc na klucze użytkownika. DSU zajmuje 2 dodatkowe miejsca na klucze. Jeśli producent OEM ma HAL tkacza, musi mieć wystarczającą liczbę gniazd na podstawowy obraz systemu (GSI) i obraz hosta.

Warstwa HAL funkcji Gatekeeper

Gatekeeper HAL musi obsługiwać duże wartości USER_ID, ponieważ GSI przesuwa identyfikatory UID do HAL o +1000000.

Weryfikacja podczas uruchamiania

Jeśli chcesz obsługiwać uruchamianie obrazów GSI dla deweloperówstanie ZABLOKOWANYM bez wyłączania weryfikacji rozruchu, uwzględnij klucze GSI dla deweloperów, dodając ten wiersz do pliku device/<device_name>/device.mk:

$(call inherit-product, $(SRC_TARGET_DIR)/product/developer_gsi_keys.mk)

Ochrona przed cofnięciem

W przypadku korzystania z DSU pobrany obraz systemu Android musi być nowszy niż obecny obraz systemu na urządzeniu. Odbywa się to przez porównanie poziomów poprawek zabezpieczeń w zweryfikowanym rozruchu Androida (AVB) deskryptora właściwości AVB obu obrazów systemu: Prop: com.android.build.system.security_patch -> '2019-04-05'.

W przypadku urządzeń, które nie korzystają z AVB, umieść poziom aktualizacji zabezpieczeń bieżącego obrazu systemu w wierszu poleceń jądra lub w konfiguracji rozruchu za pomocą programu ładującego:androidboot.system.security_patch=2019-04-05.

Wymagania sprzętowe

Podczas uruchamiania instancji DSU przydzielane są 2 pliki tymczasowe:

  • Partycja logiczna do przechowywania GSI.img (1–1,5 GB)
  • pustą partycję /data GB jako piaskownicę do uruchamiania GSI;

Przed uruchomieniem instancji DSU zalecamy zarezerwowanie co najmniej 10 GB wolnego miejsca. DSU obsługuje też przydzielanie miejsca na karcie SD. Gdy karta SD jest obecna, ma najwyższy priorytet w przydzielaniu miejsca. Obsługa kart SD jest kluczowa w przypadku urządzeń o mniejszej mocy, które mogą nie mieć wystarczającej ilości pamięci wewnętrznej. Jeśli karta SD jest włożona, upewnij się, że nie jest zaadoptowana. DSU nie obsługuje zaadoptowanych kart SD.

Dostępne interfejsy

DSU możesz uruchomić za pomocą adb, aplikacji OEM lub narzędzia do uruchamiania DSU jednym kliknięciem (w Androidzie 11 lub nowszym).

Uruchamianie DSU za pomocą adb

Aby uruchomić DSU za pomocą adb, wpisz te polecenia:

$ simg2img out/target/product/.../system.img system.raw
$ gzip -c system.raw > system.raw.gz
$ adb push system.raw.gz /storage/emulated/0/Download
$ adb shell am start-activity \
-n com.android.dynsystem/com.android.dynsystem.VerificationActivity  \
-a android.os.image.action.START_INSTALL    \
-d file:///storage/emulated/0/Download/system.raw.gz  \
--el KEY_SYSTEM_SIZE $(du -b system.raw|cut -f1)  \
--el KEY_USERDATA_SIZE 8589934592

Uruchamianie DSU za pomocą aplikacji

Głównym punktem wejścia do DSU jest android.os.image.DynamicSystemClient.java interfejs API:

public class DynamicSystemClient {


...
...

     /**
     * Start installing DynamicSystem from URL with default userdata size.
     *
     * @param systemUrl A network URL or a file URL to system image.
     * @param systemSize size of system image.
     */
    public void start(String systemUrl, long systemSize) {
        start(systemUrl, systemSize, DEFAULT_USERDATA_SIZE);
    }

Musisz dołączyć tę aplikację do urządzenia lub wstępnie ją na nim zainstalować. Ponieważ DynamicSystemClient jest interfejsem API systemu, nie możesz skompilować aplikacji za pomocą zwykłego interfejsu API pakietu SDK ani opublikować jej w Google Play. Cel tej aplikacji:

  1. Pobieranie listy obrazów i odpowiedniego adresu URL ze schematem zdefiniowanym przez dostawcę.
  2. Dopasuj obrazy na liście do urządzenia i wyświetl użytkownikowi zgodne obrazy do wyboru.
  3. Wywołaj DynamicSystemClient.start w ten sposób:

    DynamicSystemClient aot = new DynamicSystemClient(...)
       aot.start(
            ...URL of the selected image...,
            ...uncompressed size of the selected image...);
    
    

Adres URL wskazuje skompresowany plik obrazu systemu, który nie jest rzadki. Możesz go utworzyć za pomocą tych poleceń:

$ simg2img ${OUT}/system.img ${OUT}/system.raw
$ gzip ${OUT}/system.raw
$ ls ${OUT}/system.raw.gz

Nazwa pliku powinna mieć format:

<android version>.<lunch name>.<user defined title>.raw.gz

Przykłady:

  • o.aosp_taimen-userdebug.2018dev.raw.gz
  • p.aosp_taimen-userdebug.2018dev.raw.gz

Ładowanie DSU jednym kliknięciem

Android 11 wprowadza ładowarkę DSU, która jest interfejsem w ustawieniach programisty.

Uruchamianie narzędzia do ładowania DSU

Rysunek 1. Uruchamianie narzędzia do ładowania DSU

Gdy deweloper kliknie przycisk DSU Loader, pobierze z internetu wstępnie skonfigurowany deskryptor JSON DSU i wyświetli wszystkie odpowiednie obrazy w menu pływającym. Wybierz obraz, aby rozpocząć instalację DSU. Postęp będzie widoczny na pasku powiadomień.

Postęp instalacji obrazu DSU

Rysunek 2. Postęp instalacji obrazu DSU

Domyślnie program wczytujący DSU wczytuje deskryptor JSON zawierający obrazy GSI. W sekcjach poniżej pokazujemy, jak tworzyć pakiety DSU podpisane przez producenta OEM i ładować je z programu do ładowania DSU.

Flaga funkcji

Funkcja DSU jest dostępna pod settings_dynamic_android flagą funkcji. Zanim zaczniesz korzystać z DSU, upewnij się, że odpowiednia flaga funkcji jest włączona.

Włączanie flagi funkcji.

Rysunek 3. Włączanie flagi funkcji

Interfejs flagi funkcji może być niedostępny na urządzeniu z wersją użytkownika. W takim przypadku użyj polecenia adb:

$ adb shell setprop persist.sys.fflag.override.settings_dynamic_system 1

Obrazy systemu hosta dostawcy w GCE (opcjonalnie)

Jedną z możliwych lokalizacji przechowywania obrazów systemu jest zasobnik Google Compute Engine (GCE). Administrator wersji używa konsoli pamięci GCP, aby dodawać, usuwać i zmieniać wydany obraz systemu.

Obrazy muszą być publicznie dostępne, jak pokazano tutaj:

Dostęp publiczny w GCE

Rysunek 4. Dostęp publiczny w GCE

Procedura udostępniania elementu publicznie jest opisana w dokumentacji Google Cloud.

DSU z wieloma partycjami w pliku ZIP

Od Androida 11 DSU może mieć więcej niż 1 partycję. Może na przykład zawierać product.img oprócz system.img. Podczas uruchamiania urządzenia pierwszy etap init wykrywa zainstalowane partycje DSU i tymczasowo zastępuje partycję na urządzeniu, gdy zainstalowana DSU jest włączona. Pakiet DSU może zawierać partycję, która nie ma odpowiednika na urządzeniu.

Proces DSU z wieloma partycjami

Rysunek 5. Proces DSU z wieloma partycjami

DSU podpisany przez producenta OEM

Aby mieć pewność, że wszystkie obrazy działające na urządzeniu są autoryzowane przez producenta urządzenia, wszystkie obrazy w pakiecie DSU muszą być podpisane. Załóżmy na przykład, że istnieje pakiet DSU, który zawiera 2 obrazy partycji, jak poniżej:

dsu.zip {
    - system.img
    - product.img
}

Zarówno plik system.img, jak i product.img muszą być podpisane kluczem OEM, zanim zostaną umieszczone w pliku ZIP. Zwykle używa się algorytmu asymetrycznego, np. RSA, w którym klucz tajny służy do podpisywania pakietu, a klucz publiczny do jego weryfikacji. Pierwszy etap ramdysku musi zawierać klucz publiczny parowania, np. /avb/*.avbpubkey. Jeśli urządzenie obsługuje już AVB, wystarczy dotychczasowa procedura podpisywania. W kolejnych sekcjach przedstawiamy proces podpisywania i wyjaśniamy, gdzie znajduje się klucz publiczny AVB, który służy do weryfikacji obrazów w pakiecie DSU.

Deskryptor JSON DSU

Deskryptor JSON DSU opisuje pakiety DSU. Obsługuje 2 typy danych. Po pierwsze, include zawiera dodatkowe deskryptory JSON lub przekierowuje moduł wczytujący DSU do nowej lokalizacji. Na przykład:

{
    "include": ["https://.../gsi-release/gsi-src.json"]
}

Po drugie, do opisywania opublikowanych pakietów DSU używany jest element image. W elemencie obrazu znajduje się kilka atrybutów:

  • Atrybuty namedetails to ciągi tekstowe, które są wyświetlane w oknie dialogowym, aby użytkownik mógł je wybrać.

  • Atrybuty cpu_api, vndk i os_version są używane do sprawdzania zgodności, które opisujemy w następnej sekcji.

  • Opcjonalny atrybut pubkey opisuje klucz publiczny, który jest powiązany z kluczem tajnym używanym do podpisywania pakietu DSU. Gdy jest określony, usługa DSU może sprawdzić, czy urządzenie ma klucz używany do weryfikacji pakietu DSU. Zapobiega to instalowaniu nierozpoznanego pakietu DSU, np. instalowaniu pakietu DSU podpisanego przez OEM-A na urządzeniu wyprodukowanym przez OEM-B.

  • Opcjonalny atrybut tos wskazuje plik tekstowy, który opisuje warunki korzystania z usługi dla odpowiedniego pakietu DSU. Gdy deweloper wybierze pakiet DSU z określonym atrybutem warunków usługi, otworzy się okno dialogowe widoczne na ilustracji 6, w którym deweloper zostanie poproszony o zaakceptowanie warunków usługi przed zainstalowaniem pakietu DSU.

    Okno Warunków korzystania z usługi

    Rysunek 6. Okno Warunków korzystania z usługi

Oto przykładowy deskryptor JSON DSU dla GSI:

{
   "images":[
      {
         "name":"GSI+GMS x86",
         "os_version":"10",
         "cpu_abi": "x86",
         "details":"exp-QP1A.190711.020.C4-5928301",
         "vndk":[
            27,
            28,
            29
         ],
         "pubkey":"",
         "tos": "https://dl.google.com/developers/android/gsi/gsi-tos.txt",
         "uri":"https://.../gsi/gsi_gms_x86-exp-QP1A.190711.020.C4-5928301.zip"
      },
      {
         "name":"GSI+GMS ARM64",
         "os_version":"10",
         "cpu_abi": "arm64-v8a",
         "details":"exp-QP1A.190711.020.C4-5928301",
         "vndk":[
            27,
            28,
            29
         ],
         "pubkey":"",
         "tos": "https://dl.google.com/developers/android/gsi/gsi-tos.txt",
         "uri":"https://.../gsi/gsi_gms_arm64-exp-QP1A.190711.020.C4-5928301.zip"
      },
      {
         "name":"GSI ARM64",
         "os_version":"10",
         "cpu_abi": "arm64-v8a",
         "details":"exp-QP1A.190711.020.C4-5928301",
         "vndk":[
            27,
            28,
            29
         ],
         "pubkey":"",
         "uri":"https://.../gsi/aosp_arm64-exp-QP1A.190711.020.C4-5928301.zip"
      },
      {
         "name":"GSI x86_64",
         "os_version":"10",
         "cpu_abi": "x86_64",
         "details":"exp-QP1A.190711.020.C4-5928301",
         "vndk":[
            27,
            28,
            29
         ],
         "pubkey":"",
         "uri":"https://.../gsi/aosp_x86_64-exp-QP1A.190711.020.C4-5928301.zip"
      }
   ]
}

Zarządzanie zgodnością

Do określania zgodności pakietu DSU z urządzeniem lokalnym służy kilka atrybutów:

  • cpu_api to ciąg znaków opisujący architekturę urządzenia. Ten atrybut jest wymagany i jest porównywany z właściwością systemową ro.product.cpu.abi. Wartości muszą być dokładnie takie same.

  • os_version to opcjonalna liczba całkowita określająca wersję Androida. Na przykład w Androidzie 10 os_version to 10, a w Androidzie 11 os_version to 11. Jeśli ten atrybut jest określony, musi być równy lub większy niż właściwość systemowa ro.system.build.version.release. To sprawdzenie zapobiega uruchamianiu obrazu GSI Androida 10 na urządzeniu dostawcy z Androidem 11, co obecnie nie jest obsługiwane. Uruchamianie obrazu GSI Androida 11 na urządzeniu z Androidem 10 jest dozwolone.

  • vndk to opcjonalna tablica, która określa wszystkie VNDK zawarte w pakiecie DSU. Gdy jest określony, program wczytujący DSU sprawdza, czy numer wyodrębniony z właściwości systemowej ro.vndk.version jest uwzględniony.

Unieważnianie kluczy DSU ze względów bezpieczeństwa

W bardzo rzadkich przypadkach, gdy para kluczy RSA używana do podpisywania obrazów DSU zostanie naruszona, dysk RAM powinien zostać jak najszybciej zaktualizowany, aby usunąć naruszony klucz. Oprócz aktualizowania partycji rozruchowej możesz blokować naruszone klucze za pomocą listy odwołań kluczy DSU (czarnej listy kluczy) z adresu URL HTTPS.

Lista unieważnionych kluczy DSU zawiera listę unieważnionych kluczy publicznych AVB. Podczas instalacji DSU klucze publiczne w obrazach DSU są weryfikowane za pomocą listy odwołań. Jeśli obrazy zawierają odwołany klucz publiczny, proces instalacji DSU zostanie zatrzymany.

Adres URL listy unieważnionych kluczy powinien być adresem URL HTTPS, aby zapewnić bezpieczeństwo. Jest on określony w ciągu zasobu:

frameworks/base/packages/DynamicSystemInstallationService/res/values/strings.xml@key_revocation_list_url

Wartość ciągu to https://dl.google.com/developers/android/gsi/gsi-keyblacklist.json, czyli lista unieważnień kluczy GSI wydanych przez Google. Ten ciąg zasobu można nakładać i dostosowywać, dzięki czemu producenci OEM, którzy korzystają z funkcji DSU, mogą udostępniać i utrzymywać własną czarną listę kluczy. Dzięki temu producent OEM może blokować niektóre klucze publiczne bez aktualizowania obrazu dysku RAM urządzenia.

Format listy odwołań to:

{
   "entries":[
      {
         "public_key":"bf14e439d1acf231095c4109f94f00fc473148e6",
         "status":"REVOKED",
         "reason":"Key revocation test key"
      },
      {
         "public_key":"d199b2f29f3dc224cca778a7544ea89470cbef46",
         "status":"REVOKED",
         "reason":"Key revocation test key"
      }
   ]
}
  • public_key to skrót SHA-1 odwołanego klucza w formacie opisanym w sekcji generowanie klucza publicznego AVB.
  • status wskazuje stan unieważnienia klucza. Obecnie jedyną obsługiwaną wartością jest REVOKED.
  • reason to opcjonalny ciąg znaków opisujący przyczynę unieważnienia.

Procedury DSU

W tej sekcji opisujemy, jak wykonać kilka procedur konfiguracji DSU.

Generowanie nowej pary kluczy

Aby wygenerować parę kluczy RSA (prywatny i publiczny) w formacie .pem, użyj polecenia openssl (np. o rozmiarze 2048 bitów):

$ openssl genrsa -out oem_cert_pri.pem 2048
$ openssl rsa -in oem_cert_pri.pem -pubout -out oem_cert_pub.pem

Klucz prywatny może być niedostępny i jest przechowywany tylko w sprzętowym module zabezpieczeń (HSM). W takim przypadku po wygenerowaniu klucza może być dostępny certyfikat klucza publicznego x509. Instrukcje generowania klucza publicznego AVB z certyfikatu x509 znajdziesz w sekcji Dodawanie klucza publicznego parowania do dysku RAM.

Aby przekonwertować certyfikat x509 na format PEM:

$ openssl x509 -pubkey -noout -in oem_cert_pub.x509.pem > oem_cert_pub.pem

Pomiń ten krok, jeśli certyfikat jest już plikiem PEM.

Dodaj klucz publiczny parowania do dysku RAM.

Aby zweryfikować podpisany pakiet DSU, element oem_cert.avbpubkey musi być umieszczony w obrębie elementu /avb/*.avbpubkey. Najpierw przekonwertuj klucz publiczny w formacie PEM na format klucza publicznego AVB:

$ avbtool extract_public_key --key oem_cert_pub.pem --output oem_cert.avbpubkey

Następnie wykonaj te czynności, aby dodać klucz publiczny do dysku RAM pierwszego etapu.

  1. Dodaj gotowy moduł, aby skopiować avbpubkey. Na przykład dodaj pola device/<company>/<board>/oem_cert.avbpubkeydevice/<company>/<board>/avb/Android.mk z treściami w tym stylu:

    include $(CLEAR_VARS)
    
    LOCAL_MODULE := oem_cert.avbpubkey
    LOCAL_MODULE_CLASS := ETC
    LOCAL_SRC_FILES := $(LOCAL_MODULE)
    ifeq ($(BOARD_USES_RECOVERY_AS_BOOT),true)
    LOCAL_MODULE_PATH := $(TARGET_RECOVERY_ROOT_OUT)/first_stage_ramdisk/avb
    else
    LOCAL_MODULE_PATH := $(TARGET_RAMDISK_OUT)/avb
    endif
    
    include $(BUILD_PREBUILT)
    
  2. Spraw, aby cel droidcore zależał od dodanego oem_cert.avbpubkey:

    droidcore: oem_cert.avbpubkey
    

Wygeneruj atrybut klucza publicznego AVB w deskryptorze JSON.

oem_cert.avbpubkey jest w binarnym formacie klucza publicznego AVB. Użyj SHA-1, aby przed umieszczeniem w deskryptorze JSON uczynić go czytelnym:

$ sha1sum oem_cert.avbpubkey | cut -f1 -d ' '
3e62f2be9d9d813ef5........866ac72a51fd20

Będzie to zawartość atrybutu pubkey deskryptora JSON.

   "images":[
      {
         ...
         "pubkey":"3e62f2be9d9d813ef5........866ac72a51fd20",
         ...
      },

Podpisywanie pakietu DSU

Aby podpisać pakiet DSU, użyj jednej z tych metod:

  • Metoda 1. Ponowne użycie artefaktu utworzonego w procesie podpisywania AVB w celu utworzenia pakietu DSU. Innym rozwiązaniem jest wyodrębnienie z pakietu wersji już podpisanych obrazów i użycie ich do bezpośredniego utworzenia pliku ZIP.

  • Metoda 2. Jeśli klucz prywatny jest dostępny, użyj tych poleceń, aby podpisać partycje DSU. Każdy plik img w pakiecie DSU (plik ZIP) jest podpisany osobno:

    $ key_len=$(openssl rsa -in oem_cert_pri.pem -text | grep Private-Key | sed -e 's/.*(\(.*\) bit.*/\1/')
    $ for partition in system product; do
        avbtool add_hashtree_footer \
            --image ${OUT}/${partition}.img \
            --partition_name ${partition} \
            --algorithm SHA256_RSA${key_len} \
            --key oem_cert_pri.pem
    done
    

Więcej informacji o dodawaniu add_hashtree_footer za pomocą avbtool znajdziesz w artykule Korzystanie z narzędzia avbtool.

Weryfikowanie pakietu DSU lokalnie

Zalecamy sprawdzenie wszystkich lokalnych obrazów za pomocą klucza publicznego parowania za pomocą tych poleceń:


for partition in system product; do
    avbtool verify_image --image ${OUT}/${partition}.img  --key oem_cert_pub.pem
done

Oczekiwane dane wyjściowe wyglądają tak:

Verifying image dsu/system.img using key at oem_cert_pub.pem
vbmeta: Successfully verified footer and SHA256_RSA2048 vbmeta struct in dsu/system.img
: Successfully verified sha1 hashtree of dsu/system.img for image of 898494464 bytes

Verifying image dsu/product.img using key at oem_cert_pub.pem
vbmeta: Successfully verified footer and SHA256_RSA2048 vbmeta struct in dsu/product.img
: Successfully verified sha1 hashtree of dsu/product.img for image of 905830400 bytes

Tworzenie pakietu DSU

W tym przykładzie tworzymy pakiet DSU, który zawiera system.imgproduct.img:

dsu.zip {
    - system.img
    - product.img
}

Po podpisaniu obu obrazów użyj tego polecenia, aby utworzyć plik ZIP:

$ mkdir -p dsu
$ cp ${OUT}/system.img dsu
$ cp ${OUT}/product.img dsu
$ cd dsu && zip ../dsu.zip *.img && cd -

Dostosowywanie DSU jednym kliknięciem

Domyślnie program wczytujący DSU wskazuje metadane obrazów GSI, które sąhttps://...google.com/.../gsi-src.json.

Producenci OEM mogą nadpisać listę, definiując właściwość persist.sys.fflag.override.settings_dynamic_system.list, która wskazuje ich własny deskryptor JSON. Na przykład producent OEM może udostępnić metadane JSON, które zawierają GSI oraz obrazy własne producenta OEM, takie jak:

{
    "include": ["https://dl.google.com/.../gsi-src.JSON"]
    "images":[
      {
         "name":"OEM image",
         "os_version":"10",
         "cpu_abi": "arm64-v8a",
         "details":"...",
         "vndk":[
            27,
            28,
            29
         ],
         "spl":"...",
         "pubkey":"",
         "uri":"https://.../....zip"
      },

}

Producent OEM może połączyć opublikowane metadane DSU w łańcuch, jak pokazano na rysunku 7.

Łączenie opublikowanych metadanych DSU

Rysunek 7. Łączenie opublikowanych metadanych DSU