Android 11 rozdziela partycję product
, czyniąc ją niezależną od partycji system
i vendor
. W ramach tych zmian można teraz kontrolować dostęp partycji product
do interfejsów natywnych i interfejsów Java (co jest podobne do sposobu, w jaki działa wymuszanie interfejsu w przypadku partycji vendor
).
Wymuszanie natywnych interfejsów
Aby włączyć wymuszanie interfejsu natywnego, ustaw PRODUCT_PRODUCT_VNDK_VERSION
na current
. (Wersja jest automatycznie ustawiana na current
, gdy poziom API wysyłki dla miejsca docelowego jest większy niż 29.) Egzekwowanie umożliwia:
- Natywne moduły w partycji
product
do połączenia:- Statycznie lub dynamicznie do innych modułów w partycji
product
, które zawierają biblioteki statyczne, współdzielone lub nagłówkowe. - Dynamicznie do bibliotek VNDK na partycji
system
.
- Statycznie lub dynamicznie do innych modułów w partycji
- Biblioteki JNI w uwolnionych plikach APK na partycji
product
w celu połączenia z bibliotekami w/product/lib
lub/product/lib64
(jest to dodatek do bibliotek NDK).
Wymuszanie nie pozwala na inne łącza do partycji innych niż partycja product
.
Egzekwowanie czasu kompilacji (Android.bp)
W systemie Android 11 moduły systemu mogą tworzyć warianty obrazu produktu oprócz wariantów obrazu rdzenia i dostawcy. Gdy włączone jest wymuszanie interfejsu natywnego ( PRODUCT_PRODUCT_VNDK_VERSION
jest ustawione na current
):
Moduły natywne w partycji
product
znajdują się w wariancie produktu, a nie w wariancie rdzenia.Moduły z
product_available: true
w swoich plikachAndroid.bp
są dostępne dla wariantu produktu.Biblioteki lub pliki binarne, które określają
product_specific: true
mogą łączyć się z innymi bibliotekami, które w swoich plikachAndroid.bp
określająproduct_specific: true
lubproduct_available: true
.Biblioteki VNDK muszą mieć
product_available: true
w swoich plikachAndroid.bp
, aby pliki binarneproduct
mogły łączyć się z bibliotekami VNDK.
W poniższej tabeli podsumowano właściwości Android.bp
używane do tworzenia wariantów obrazu.
Właściwości w Android.bp | Utworzono warianty | |
---|---|---|
Przed wykonaniem | Po wykonaniu | |
domyślny (brak) | rdzeń (zawiera | rdzeń (zawiera |
system_ext_specific: true | rdzeń | rdzeń |
product_specific: true | rdzeń | produkt |
vendor: true | sprzedawca | sprzedawca |
vendor_available: true | rdzeń, sprzedawca | rdzeń, sprzedawca |
product_available: true | Nie dotyczy | rdzeń, produkt |
vendor_available: true ORAZ product_available: true | Nie dotyczy | rdzeń, produkt, dostawca |
system_ext_specific: true ORAZ vendor_available: true | rdzeń, sprzedawca | rdzeń, sprzedawca |
product_specific: true ORAZ vendor_available: true | rdzeń, sprzedawca | produkt, sprzedawca |
Egzekwowanie czasu kompilacji (Android.mk)
Gdy włączone jest wymuszanie interfejsu natywnego, moduły natywne zainstalowane na partycji product
mają typ łącza native:product
, który może łączyć się tylko z innymi modułami native:product
lub native:vndk
. Próba połączenia z modułami innymi niż te powoduje, że system kompilacji generuje błąd sprawdzania typu łącza.
Egzekwowanie czasu wykonania
Gdy włączone jest wymuszanie interfejsu natywnego, konfiguracja linkera dla linkera bionicznego nie pozwala procesom systemowym na korzystanie z bibliotek product
, tworząc sekcję product
dla procesów product
, które nie mogą łączyć się z bibliotekami znajdującymi się poza partycją product
(jednak takie procesy mogą link do bibliotek VNDK). Próby naruszenia konfiguracji łącza w czasie wykonywania powodują awarię procesu i wygenerowanie komunikatu o błędzie CANNOT LINK EXECUTABLE
.
Egzekwowanie interfejsów Java
Aby włączyć wymuszanie interfejsu Java, ustaw PRODUCT_ENFORCE_PRODUCT_PARTITION_INTERFACE
na true
. (Wartość jest automatycznie ustawiana na true
, gdy poziom interfejsu API wysyłki dla miejsca docelowego jest większy niż 29.) Po włączeniu wymuszanie zezwala/zabrania następującego dostępu.
API | /system | /system_ext | /produkt | /sprzedawca | /dane |
---|---|---|---|---|---|
Publiczne API | |||||
@SystemApi | |||||
@ukryj API |
Podobnie jak w przypadku partycji vendor
, aplikacja lub biblioteka Java w partycji product
może używać wyłącznie publicznych i systemowych interfejsów API; łączenie z biblioteką korzystającą z ukrytych interfejsów API jest niedozwolone. To ograniczenie obejmuje łączenie w czasie kompilacji i odbicie w czasie wykonywania.
Buduj egzekwowanie czasu
W czasie kompilacji Make i Soong sprawdzają, czy moduły Java w partycji product
nie korzystają z ukrytych interfejsów API, sprawdzając pola platform_apis
i sdk_version
. Pole sdk_version
aplikacji w partycji product
musi być wypełnione current
, system_current
lub numeryczną wersją interfejsu API, a pole platform_apis
musi być puste.
Egzekwowanie czasu wykonania
Środowisko wykonawcze systemu Android sprawdza, czy aplikacje w partycji product
nie korzystają z ukrytych interfejsów API, w tym z refleksji. Aby uzyskać szczegółowe informacje, zobacz Ograniczenia dotyczące interfejsów innych niż SDK .
Włączanie wymuszania interfejsu produktu
Wykonaj czynności opisane w tej sekcji, aby włączyć wymuszanie interfejsu produktu.
Krok | Zadanie | Wymagany |
---|---|---|
1 | Zdefiniuj własny systemowy plik Makefile, który będzie określał pakiety dla partycji system , a następnie ustaw sprawdzanie wymagań dotyczących ścieżki artefaktów w device.mk (aby zapobiec instalowaniu na partycji system modułów niesystemowych). | N |
2 | Wyczyść listę dozwolonych. | N |
3 | Egzekwuj natywne interfejsy i identyfikuj awarie łączy w czasie wykonywania (można działać równolegle z wymuszaniem Java). | Y |
4 | Egzekwuj interfejsy Java i sprawdzaj zachowanie w czasie wykonywania (można działać równolegle z wymuszaniem natywnym). | Y |
5 | Sprawdź zachowania w czasie wykonywania. | Y |
6 | Zaktualizuj device.mk za pomocą wymuszania interfejsu produktu. | Y |
Krok 1: Utwórz plik makefile i włącz sprawdzanie ścieżki artefaktów
W tym kroku definiujesz system
makefile.
Utwórz plik makefile, który definiuje pakiety dla partycji
system
. Na przykład utwórz plikoem_system.mk
zawierający następujące elementy:$(call inherit-product, $(SRC_TARGET_DIR)/product/handheld_system.mk) $(call inherit-product, $(SRC_TARGET_DIR)/product/telephony_system.mk) # Applications PRODUCT_PACKAGES += \ CommonSystemApp1 \ CommonSystemApp2 \ CommonSystemApp3 \ # Binaries PRODUCT_PACKAGES += \ CommonSystemBin1 \ CommonSystemBin2 \ CommonSystemBin3 \ # Libraries PRODUCT_PACKAGES += \ CommonSystemLib1 \ CommonSystemLib2 \ CommonSystemLib3 \ PRODUCT_SYSTEM_NAME := oem_system PRODUCT_SYSTEM_BRAND := Android PRODUCT_SYSTEM_MANUFACTURER := Android PRODUCT_SYSTEM_MODEL := oem_system PRODUCT_SYSTEM_DEVICE := generic # For system-as-root devices, system.img should be mounted at /, so we # include ROOT here. _my_paths := \ $(TARGET_COPY_OUT_ROOT)/ \ $(TARGET_COPY_OUT_SYSTEM)/ \ $(call require-artifacts-in-path, $(_my_paths),)
W pliku
device.mk
odziedzicz wspólny plik makefile dla partycjisystem
i włącz sprawdzanie wymagań dotyczących ścieżki artefaktów. Na przykład:$(call inherit-product, $(SRC_TARGET_DIR)/product/oem_system.mk) # Enable artifact path requirements checking PRODUCT_ENFORCE_ARTIFACT_PATH_REQUIREMENTS := strict
Informacje o wymaganiach dotyczących ścieżki artefaktów
Gdy PRODUCT_ENFORCE_ARTIFACT_PATH_REQUIREMENTS
jest ustawione na true
lub strict
, system kompilacji uniemożliwia instalowanie pakietów zdefiniowanych w innych plikach makefile na ścieżkach zdefiniowanych w require-artifacts-in-path
i zapobiega instalowaniu artefaktów zdefiniowanych w bieżącym pliku makefile poza ścieżkami zdefiniowanymi w require-artifacts-in-path
.
W powyższym przykładzie, gdy PRODUCT_ENFORCE_ARTIFACT_PATH_REQUIREMENTS
jest ustawione na strict
, pliki makefile poza oem_system.mk
nie mogą zawierać modułów zainstalowanych na partycji root
lub system
. Aby dołączyć te moduły, musisz je zdefiniować w samym pliku oem_system.mk
lub w dołączonym pliku makefile. Próby zainstalowania modułów w niedozwolonych ścieżkach powodują przerwy w kompilacji. Aby naprawić przerwy, wykonaj jedną z następujących czynności:
Opcja 1: Dołącz moduł systemowy do plików makefile zawartych w
oem_system.mk
. To sprawia, że wymagania dotyczące ścieżki artefaktów są spełnione (ponieważ moduły istnieją teraz w dołączonym pliku makefile), co umożliwia instalację do zestawu ścieżek w `require-artifacts-in-path.Opcja 2: Zainstaluj moduły na partycji
system_ext
lub partycjiproduct
(i nie instaluj modułów na partycjisystem
).Opcja 3: Dodaj moduły do
PRODUCT_ARTIFACT_PATH_REQUIREMENT_ALLOWED_LIST
. Ta lista zawiera dozwolone moduły do zainstalowania.
Krok 2: Opróżnij listę dozwolonych
W tym kroku powodujesz, że PRODUCT_ARTIFACT_PATH_REQUIREMENT_ALLOWED_LIST
jest pusta, aby wszystkie urządzenia współdzielące oem_system.mk
mogły także współużytkować pojedynczy obraz system
. Aby opróżnić listę dozwolonych, przenieś dowolne moduły z listy do partycji system_ext
lub partycji product
albo dodaj je do system
plików make. Ten krok jest opcjonalny, ponieważ zdefiniowanie wspólnego obrazu system
nie jest wymagane do umożliwienia egzekwowania interfejsu produktu. Jednak opróżnienie listy dozwolonych jest pomocne przy definiowaniu granicy system
za pomocą system_ext
.
Krok 3: Wymuś natywne interfejsy
W tym kroku ustawisz PRODUCT_PRODUCT_VNDK_VERSION := current
, a następnie wyszukasz błędy kompilacji i wykonania i rozwiążesz je. Aby sprawdzić rozruch urządzenia i dzienniki oraz znaleźć i naprawić awarie łączy w czasie wykonywania:
Ustaw
PRODUCT_PRODUCT_VNDK_VERSION := current
.Zbuduj urządzenie i poszukaj błędów kompilacji. Prawdopodobnie zobaczysz kilka przerw w kompilacji z powodu brakujących wariantów produktu lub wariantów podstawowych. Typowe przerwy obejmują:
- Żaden moduł
hidl_interface
, który maproduct_specific: true
nie będzie dostępny dla modułów systemowych. Aby to naprawić, zamieńproduct_specific: true
nasystem_ext_specfic: true
. - W modułach może brakować wariantu produktu wymaganego dla modułów produktu. Aby to naprawić, udostępnij ten moduł partycji
product
, ustawiającproduct_available: true
lub przenieś moduł na partycjęproduct
, ustawiającproduct_specific: true
.
- Żaden moduł
Rozwiąż błędy kompilacji i upewnij się, że urządzenie pomyślnie się zbudowało.
Flashuj obraz i poszukaj błędów wykonawczych w rozruchu urządzenia i dziennikach.
- Jeśli tag
linker
z dziennika przypadków testowych wyświetla komunikatCANNOT LINK EXECUTABLE
, w pliku make brakuje zależności (i nie został on przechwycony w czasie kompilacji). - Aby to sprawdzić z systemu kompilacji, dodaj wymaganą bibliotekę do pola
shared_libs:
lubrequired:
- Jeśli tag
Rozwiąż brakujące zależności, korzystając ze wskazówek podanych powyżej.
Krok 4: Wymuś interfejsy Java
W tym kroku ustawisz PRODUCT_ENFORCE_PRODUCT_PARTITION_INTERFACE := true
, a następnie znajdziesz i naprawisz powstałe błędy kompilacji. Poszukaj dwóch konkretnych typów błędów:
Błędy typu łącza. Ten błąd wskazuje, że aplikacja łączy się z modułami Java, które mają szerszą
sdk_version
. Aby to naprawić, możesz rozszerzyćsdk_version
aplikacji lub ograniczyćsdk_version
biblioteki. Przykładowy błąd:error: frameworks/base/packages/SystemUI/Android.bp:138:1: module "SystemUI" variant "android_common": compiles against system API, but dependency "telephony-common" is compiling against private API.Adjust sdk_version: property of the source or target module so that target module is built with the same or smaller API set than the source.
Błędy symboli. Ten błąd wskazuje, że nie można znaleźć symbolu, ponieważ znajduje się on w ukrytym interfejsie API. Aby to naprawić, użyj widocznego (nieukrytego) interfejsu API lub znajdź alternatywę. Przykładowy błąd:
frameworks/opt/net/voip/src/java/com/android/server/sip/SipSessionGroup.java:1051: error: cannot find symbol ProxyAuthenticate proxyAuth = (ProxyAuthenticate)response.getHeader( ^ symbol: class ProxyAuthenticate location: class SipSessionGroup.SipSessionImpl
Krok 5: Sprawdź zachowania w czasie wykonywania
Na tym etapie sprawdzasz, czy zachowania środowiska wykonawczego są zgodne z oczekiwaniami. W przypadku aplikacji, które można debugować, możesz monitorować użycie ukrytego interfejsu API za pomocą dziennika przy użyciu StrictMode.detectNonSdkApiUsage
(który generuje dziennik, gdy aplikacja korzysta z ukrytego interfejsu API). Alternatywnie możesz użyć narzędzia analizy statycznej Veridex , aby uzyskać typ użycia (łączenie lub odbicie), poziom ograniczeń i stos wywołań.
Składnia Veridexu:
./art/tools/veridex/appcompat.sh --dex-file={apk file}
Przykładowy wynik Veridex:
#1: Linking greylist-max-o Landroid/animation/AnimationHandler;-><init>()V use(s): Lcom/android/systemui/pip/phone/PipMotionHelper;-><init>(Landroid/content/Context;Landroid/app/IActivityManager;Landroid/app/IActivityTaskManager;Lcom/android/systemui/pip/phone/PipMenuActivityController;Lcom/android/internal/policy/PipSnapAlgorithm;Lcom/android/systemui/statusbar/FlingAnimationUtils;)V #1332: Reflection greylist Landroid/app/Activity;->mMainThread use(s): Landroidx/core/app/ActivityRecreator;->getMainThreadField()Ljava/lang/reflect/Field;
Aby uzyskać szczegółowe informacje na temat użycia Veridex, zobacz Testowanie za pomocą narzędzia Veridex .
Krok 6: Zaktualizuj Device.mk
Po naprawieniu wszystkich błędów kompilacji i środowiska wykonawczego oraz sprawdzeniu, czy zachowania środowiska wykonawczego są zgodne z oczekiwaniami, ustaw następujące ustawienia w device.mk
:
-
PRODUCT_PRODUCT_VNDK_VERSION := current
-
PRODUCT_ENFORCE_PRODUCT_PARTITION_INTERFACE := true