Microdroid to miniwersja Androida działająca w pVM. Nie musisz używać Microdroida – możesz uruchomić maszynę wirtualną z dowolnym systemem operacyjnym. Głównym zastosowaniem pVM nie jest jednak uruchamianie samodzielnego systemu operacyjnego, ale oferowanie izolowanego środowiska wykonawczego do uruchamiania części aplikacji z większymi gwarancjami poufności i integralności niż w przypadku Androida.
W przypadku tradycyjnych systemów operacyjnych zapewnienie wysokiego poziomu poufności i integralności wymaga sporo pracy (często powielanej), ponieważ tradycyjne systemy operacyjne nie pasują do ogólnej architektury Androida. Na przykład w standardowej architekturze Androida deweloperzy muszą zaimplementować sposób bezpiecznego wczytywania i wykonywania części aplikacji w pVM, a ładunek jest tworzony na podstawie glibc. Aplikacja na Androida używa Bionic, komunikacja wymaga niestandardowego protokołu przez vsock, a debugowanie za pomocą adb jest trudne.
Microdroid wypełnia te luki, udostępniając gotowy obraz systemu operacyjnego, który wymaga od deweloperów minimalnego wysiłku, aby przenieść część aplikacji do pVM. Kod natywny jest tworzony na podstawie Bionic, komunikacja odbywa się przez Binder, a Microdroid umożliwia importowanie APEX z hosta Androida i udostępnia podzbiór interfejsu Android API, np. keystore do operacji kryptograficznych z kluczami obsługiwanymi przez sprzęt. Deweloperzy powinni uznać Microdroida za znajome środowisko z narzędziami, do których przywykli w pełnej wersji systemu operacyjnego Android.
Funkcje
Microdroid to uproszczona wersja Androida z kilkoma dodatkowymi komponentami specyficznymi dla pVM. Microdroid obsługuje:
- podzbiór interfejsów NDK API (udostępniane są wszystkie interfejsy API do implementacji libc i Bionic w Androidzie);
- funkcje debugowania, takie jak adb, logcat, tombstone i gdb;
- weryfikację podczas uruchamiania i SELinux;
- wczytywanie i wykonywanie pliku binarnego wraz z bibliotekami współdzielonymi, które są osadzone w pliku APK;
- Binder RPC przez vsock i wymianę plików z niejawnymi kontrolami integralności;
- wczytywanie APEX.
Microdroid nie obsługuje:
interfejsów Android Java API w pakietach
android.\*.SystemServer i Zygote;
grafiki/interfejsu;
HAL.
Architektura Microdroida
Microdroid jest podobny do Cuttlefish, ponieważ oba mają architekturę zbliżoną do standardowego Androida. Microdroid składa się z tych obrazów partycji zgrupowanych w złożonym obrazie dysku:
bootloader– weryfikuje i uruchamia jądro.boot.img– zawiera jądro i init ramdisk.vendor_boot.img– zawiera moduły jądra specyficzne dla maszyny wirtualnej, np. virtio.super.img– składa się z partycji logicznych systemu i dostawcy.vbmeta.img– zawiera metadane weryfikacji podczas uruchamiania.
Obrazy partycji są dostarczane w APEX wirtualizacji i pakowane w złożony obraz dysku przez VirtualizationService. Oprócz głównego złożonego obrazu dysku systemu operacyjnego VirtualizationService odpowiada za tworzenie tych innych partycji:
payload– zestaw partycji obsługiwanych przez APEX i APK Androida.instance– zaszyfrowana partycja do przechowywania danych weryfikacji podczas uruchamiania dla poszczególnych instancji, takich jak sól dla poszczególnych instancji, klucze publiczne zaufanych APEX i liczniki wycofywania.
Sekwencja uruchamiania
Sekwencja uruchamiania Microdroida następuje po uruchomieniu urządzenia. Uruchamianie urządzenia zostało omówione w sekcji o oprogramowaniu układowym pVM w dokumencie Architektura. Rysunek 1 przedstawia kroki wykonywane podczas sekwencji uruchamiania Microdroida:
Wyjaśnienie poszczególnych kroków:
Program rozruchowy jest wczytywany do pamięci przez crosvm, a pvmfw zaczyna się wykonywać. Zanim pvmfw przejdzie do programu rozruchowego, wykonuje 2 zadania:
- Weryfikuje program ładujący, aby sprawdzić, czy pochodzi z zaufanego źródła (Google lub producenta OEM).
- Dba o to, aby ten sam program ładujący był używany konsekwentnie podczas wielu uruchomień tej samej pVM dzięki użyciu obrazu instancji. Początkowo pVM jest uruchamiana z pustym obrazem instancji. pvmfw zapisuje tożsamość programu rozruchowego w obrazie instancji i szyfruje ją. Dzięki temu, gdy następnym razem pVM zostanie uruchomiona z tym samym obrazem instancji, pvmfw odszyfruje zapisaną tożsamość z obrazu instancji i sprawdzi, czy jest ona taka sama jak poprzednio zapisana. Jeśli tożsamości się różnią, pvmfw odmawia uruchomienia.
Program ładujący uruchamia Microdroida.
Program rozruchowy uzyskuje dostęp do dysku instancji. Podobnie jak pvmfw, program rozruchowy ma dysk instancji z informacjami o obrazach partycji używanych w tej instancji podczas poprzednich uruchomień, w tym o kluczu publicznym.
Program rozruchowy weryfikuje vbmeta i połączone partycje, takie jak
bootisuper, a jeśli weryfikacja się powiedzie, wyprowadza tajne informacje pVM na następny etap. Następnie Microdroid przekazuje kontrolę do jądra.Ponieważ partycja super została już zweryfikowana przez program rozruchowy (krok 3), jądro systemu (operacyjnego) bezwarunkowo podłącza partycję super. Podobnie jak w przypadku pełnej wersji Androida, partycja super składa się z wielu partycji logicznych zamontowanych na dm-verity. Następnie kontrola jest przekazywana do procesu
init, który uruchamia różne usługi natywne. Skryptinit.rcjest podobny do tego w pełnej wersji Androida, ale dostosowany do potrzeb Microdroida.Proces
inituruchamia menedżera Microdroida, który uzyskuje dostęp do obrazu instancji. Usługa menedżera Microdroida odszyfrowuje obraz za pomocą klucza przekazanego z poprzedniego etapu i odczytuje klucze publiczne oraz liczniki wycofywania klienta APK i APEX, którym ufa ta pVM. Te informacje są później używane przezzipfuseiapexd, gdy montują odpowiednio klienta APK i żądane APEX.Usługa menedżera Microdroida uruchamia
apexd.apexdmontuje APEX w katalogach/apex/<name>. Jedyna różnica między sposobem montowania APEX w Androidzie i Microdroidzie polega na tym, że w Microdroidzie pliki APEX pochodzą z wirtualnych urządzeń blokowych (/dev/vdc1, …), a nie ze zwykłych plików (/system/apex/*.apex).zipfuseto system plików FUSE Microdroida.zipfusemontuje klienta APK, który jest zasadniczo plikiem ZIP jako systemem plików. Pod spodem plik APK jest przekazywany jako wirtualne urządzenie blokowe przez pVM z dm-verity, tak samo jak APEX. Plik APK zawiera plik konfiguracyjny z listą APEX, o które deweloper aplikacji poprosił w przypadku tej instancji pVM. Lista jest używana przezapexdpodczas aktywowania APEX.Przepływ uruchamiania wraca do usługi menedżera Microdroida. Usługa menedżera komunikuje się następnie z
VirtualizationServiceAndroida za pomocą Binder RPC, aby zgłaszać ważne zdarzenia, takie jak awaria lub zamknięcie, oraz akceptować żądania, np. zakończenie pVM. Usługa menedżera odczytuje lokalizację głównego pliku binarnego z pliku konfiguracyjnego APK i wykonuje go.
Wymiana plików (AuthFS)
Komponenty Androida często używają plików jako danych wejściowych, wyjściowych i stanu oraz przekazują je jako deskryptory plików (typ ParcelFileDescriptor w AIDL) z dostępem kontrolowanym przez jądro Androida. AuthFS ułatwia podobną funkcję wymiany plików między wzajemnie nieufającymi sobie punktami końcowymi w obrębie pVM.
AuthFS to zasadniczo zdalny system plików z przezroczystymi kontrolami integralności poszczególnych operacji dostępu, podobny do fs-verity. Kontrole umożliwiają frontendowi, np. programowi do odczytywania plików działającemu w pVM, wykrycie, czy niezaufany backend, zwykle Android, nie naruszył zawartości pliku.
Aby wymieniać pliki, backend (fd\_server) jest uruchamiany z konfiguracją dla poszczególnych plików, która określa, czy plik jest przeznaczony do danych wejściowych (tylko do odczytu) czy wyjściowych (odczyt i zapis). W przypadku danych wejściowych frontend wymusza, aby zawartość odpowiadała znanemu skrótowi, oprócz drzewa Merkle do weryfikacji dostępu. W przypadku danych wyjściowych AuthFS wewnętrznie utrzymuje drzewo skrótów zawartości obserwowanej podczas operacji zapisu i może wymuszać integralność podczas odczytywania danych.
Podstawowy transport jest obecnie oparty na Binder RPC, ale w przyszłości może się to zmienić w celu optymalizacji wydajności.
Zarządzanie kluczami
pVM są wyposażone w stabilny klucz uszczelniający, który nadaje się do ochrony trwałych danych, oraz klucz atestacyjny, który nadaje się do tworzenia podpisów, które można zweryfikować jako wygenerowane przez pVM.
Binder RPC
Większość interfejsów Androida jest wyrażona w AIDL, które jest oparte na sterowniku jądra Binder Linux. Aby obsługiwać interfejsy między pVM, protokół Binder został przepisany tak, aby działał na gniazdach, vsock w przypadku pVM. Działanie na gniazdach umożliwia używanie istniejących interfejsów AIDL Androida w tym nowym środowisku.
Aby skonfigurować połączenie, jeden punkt końcowy, np. ładunek pVM, tworzy obiekt RpcServer, rejestruje obiekt główny i zaczyna nasłuchiwać nowych połączeń. Klienci mogą łączyć się z tym serwerem za pomocą obiektu RpcSession, pobierać obiekt Binder i używać go dokładnie tak, jak obiektu Binder używa się ze sterownikiem jądra Binder.