Android 11 rozdziela partycję product
, dzięki czemu staje się ona niezależna od partycji system
i vendor
. W ramach tych zmian możesz teraz kontrolować dostęp partycji product
do interfejsów natywnych i Java (co działa podobnie do wymuszania interfejsu w przypadku partycji vendor
).
Wymuś interfejsy natywne
Aby włączyć egzekwowanie interfejsu natywnego, ustaw PRODUCT_PRODUCT_VNDK_VERSION
na current
. (gdy poziom interfejsu API dostawy dla docelowego typu dostawy jest większy niż 29, wersja jest automatycznie ustawiana na current
). Egzekwowanie umożliwia:
- Natywne moduły w partycji
product
, które chcesz połączyć:- Statycznie lub dynamicznie do innych modułów w partycji
product
, które obejmują 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 niespakowanych plikach APK na partycji
product
, aby połączyć je z bibliotekami w folderze/product/lib
lub/product/lib64
(oprócz bibliotek NDK);
Zespół ds. egzekwowania zasad nie zezwala na inne linki do partycji niż partycja product
.
Egzekwowanie w czasie kompilacji (Android.bp)
W Androidzie 11 moduły systemowe mogą tworzyć wariant obrazu produktu oprócz podstawowych i wariantów obrazu dostawcy. Gdy jest włączone egzekwowanie interfejsu natywnego (opcja PRODUCT_PRODUCT_VNDK_VERSION
ma wartość current
):
Natywne moduły w podziale
product
znajdują się w wersji produktu, a nie w wersji podstawowej.Moduły z wartością
product_available: true
w plikuAndroid.bp
są dostępne dla wariantu produktu.Biblioteki lub pliki binarne, które podają
product_specific: true
, mogą zawierać linki do innych bibliotek, które podająproduct_specific: true
lubproduct_available: true
w plikachAndroid.bp
.Biblioteki VNDK muszą zawierać
product_available: true
w plikachAndroid.bp
, aby pliki binarneproduct
mogły się łączyć z bibliotekami VNDK.
W tabeli poniżej znajdziesz podsumowanie właściwości Android.bp
użytych do tworzenia wariantów obrazu.
Właściwości w pliku Android.bp | Utworzone warianty | |
---|---|---|
Przed egzekwowaniem | Po egzekwowaniu | |
domyślnie (brak) | podstawowe: (w tym /system , /system_ext i /product ); |
podstawowy (obejmuje /system i /system_ext , ale nie /product ) |
system_ext_specific: true |
core | core |
product_specific: true |
core | Produkt |
vendor: true |
firma | firma |
vendor_available: true |
core, vendor | core, vendor |
product_available: true |
Nie dotyczy | podstawowy, produkt |
vendor_available: true ORAZ product_available:
true |
Nie dotyczy | core, product, vendor |
system_ext_specific: true ORAZ vendor_available:
true |
core, vendor | podstawowy, dostawca |
product_specific: true ORAZ vendor_available:
true |
podstawowy, dostawca | produkt, dostawca |
Egzekwowanie w czasie kompilacji (Android.mk)
Gdy wymuszanie interfejsu natywnego jest włączone, moduły natywne zainstalowane na partycji product
mają typ połączenia native:product
, który może się łączyć tylko z innymi modułami native:product
lub native:vndk
. Próba połączenia z innymi modułami spowoduje wygenerowanie przez system kompilacji błędu sprawdzania typu linku.
Egzekwowanie w czasie działania
Gdy włączone jest wymuszanie natywnego interfejsu, konfiguracja linkera dla binarnego linkera nie zezwala procesom systemowym na korzystanie z bibliotek product
. Tworzy ona sekcję product
dla procesów product
, które nie mogą łączyć się z bibliotekami spoza partycji product
(takie procesy mogą jednak łączyć się z bibliotekami VNDK). Próby naruszenia konfiguracji linku w czasie wykonywania powodują niepowodzenie procesu i wyświetlenie komunikatu o błędzie CANNOT LINK EXECUTABLE
.
Wymuszanie interfejsów Java
Aby włączyć wymuszanie interfejsu Java, ustaw parametr PRODUCT_ENFORCE_PRODUCT_PARTITION_INTERFACE
na true
. (wartość jest automatycznie ustawiana na true
, gdy poziom interfejsu API dostawy dla celu jest większy niż 29). Po włączeniu egzekwowanie umożliwia zezwolenie lub odmowę zezwolenia na te rodzaje dostępu:
Interfejs API | /system | /system_ext | /product | /vendor | /data |
---|---|---|---|---|---|
Publiczny interfejs API | |||||
@SystemApi | |||||
@hide API |
Podobnie jak w przypadku partycji vendor
, aplikacja lub biblioteka Java w partycji product
może używać tylko publicznych i systemowych interfejsów API. Łączenie z biblioteką, która korzysta z ukrytych interfejsów API, jest niedozwolone. To ograniczenie obejmuje możliwość łączenia w czasie kompilacji i refleksji w czasie działania aplikacji.
Egzekwowanie czasu kompilacji
W momencie kompilacji Make i Soong sprawdzają, czy moduły Java w partycji product
nie używają ukrytych interfejsów API. Sprawdzają to, czy pola platform_apis
i sdk_version
są zaznaczone. Pole sdk_version
aplikacji na partycji product
musi być wypełnione wartością current
, system_current
lub numeryczną wersją interfejsu API, a pole platform_apis
musi być puste.
Egzekwowanie w czasie działania
Środowisko wykonawcze Androida sprawdza, czy aplikacje na partycji product
nie korzystają z ukrytych interfejsów API, w tym funkcji Reflection. Szczegółowe informacje znajdziesz w artykule Ograniczenia interfejsów innych niż SDK.
Włączanie egzekwowania interfejsu
Aby włączyć egzekwowanie zasad w interfejsie usługi, wykonaj czynności opisane w tej sekcji.
Krok | Zadanie | Wymagane |
---|---|---|
1 | Zdefiniuj własny plik marka systemu, który określa pakiety dla partycji system , a następnie ustaw kontrolę wymagań ścieżki artefaktów w device.mk (aby zapobiec instalowaniu modułów innych niż systemowe na partycji system ). |
N |
2 | oczyścić listę dozwolonych, | N |
3 | Wymuszanie interfejsów natywnych i identyfikowanie błędów linkowania w czasie wykonywania (można uruchamiać równolegle z wymuszaniem w Javi). | Y |
4 | Wymuszanie interfejsów Java i weryfikowanie zachowania w czasie działania (można uruchamiać równolegle z natywnym wymuszaniem). | Y |
5 | Sprawdź zachowanie podczas działania. | Y |
6 | Zaktualizuj device.mk , aby wymusić interfejs produktu. |
Y |
Krok 1. Utwórz makefile i włącz sprawdzanie ścieżki artefaktu
W tym kroku zdefiniujesz plik make system
.
Utwórz plik makefile, który definiuje pakiety dla partycji
system
. Na przykład utwórz plikoem_system.mk
z tymi danymi:$(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 make dla partycjisystem
i włącz sprawdzanie wymagań dotyczących ścieżki artefaktu. Na przykład:$(call inherit-product, $(SRC_TARGET_DIR)/product/oem_system.mk) # Enable artifact path requirements checking PRODUCT_ENFORCE_ARTIFACT_PATH_REQUIREMENTS := strict
Wymagania dotyczące ścieżki artefaktu
Gdy parametr PRODUCT_ENFORCE_ARTIFACT_PATH_REQUIREMENTS
ma wartość true
lub strict
, system kompilacji uniemożliwia instalowanie pakietów zdefiniowanych w innych plikach makefile na ścieżkach zdefiniowanych w require-artifacts-in-path
oraz uniemożliwia instalowanie artefaktów z pakietów zdefiniowanych w bieżącym pliku makefile poza ścieżkami zdefiniowanymi w require-artifacts-in-path
.
W powyższym przykładzie, gdy parametr PRODUCT_ENFORCE_ARTIFACT_PATH_REQUIREMENTS
ma wartość strict
, makefiles spoza oem_system.mk
nie mogą zawierać modułów zainstalowanych w partycji root
ani system
. Aby uwzględnić te moduły, musisz je zdefiniować w pliku oem_system.mk
lub w załączonym pliku makefile.
Próby instalacji modułów w niedozwolonych ścieżkach powodują przerwy w kompilacji. Aby naprawić przerwy, wykonaj jedną z tych czynności:
Opcja 1. Dołącz moduł systemowy do plików make zawartych w
oem_system.mk
. Dzięki temu spełnione są wymagania dotyczące ścieżki artefaktu (ponieważ moduły znajdują się teraz w załączonym pliku makefile), co umożliwia instalację w zbiorze ścieżek w pliku require-artifacts-in-path.Opcja 2. Zainstaluj moduły w partycji
system_ext
lubproduct
(nie instaluj modułów w partycjisystem
).Opcja 3. Dodaj moduły do
PRODUCT_ARTIFACT_PATH_REQUIREMENT_ALLOWED_LIST
. Lista dozwolonych modułów do zainstalowania.
Krok 2. Opróżnij listę dozwolonych
W tym kroku ustawiasz PRODUCT_ARTIFACT_PATH_REQUIREMENT_ALLOWED_LIST
na pusty, aby wszystkie urządzenia udostępniające oem_system.mk
mogły też udostępniać jeden obraz system
. Aby opróżnić listę dozwolonych, przenieś wszystkie jej moduły na partycję system_ext
lub product
albo dodaj je do system
tworzenia plików. Ten krok jest opcjonalny, ponieważ zdefiniowanie wspólnego zdjęcia system
nie jest wymagane do włączenia egzekwowania interfejsu usługi. Jednak opróżnianie listy dozwolonych jest pomocne przy definiowaniu granicy system
za pomocą system_ext
.
Krok 3. Wymuś stosowanie interfejsów natywnych
Na tym etapie ustawiasz PRODUCT_PRODUCT_VNDK_VERSION := current
, a potem sprawdzasz i naprawiasz błędy kompilacji i czasu działania. Aby sprawdzić ustawienia rozruchu urządzenia i dzienniki oraz znaleźć i naprawić błędy połączenia w środowisku wykonawczym:
Ustaw
PRODUCT_PRODUCT_VNDK_VERSION := current
.Utwórz urządzenie i sprawdź, czy nie ma błędów. Prawdopodobnie zobaczysz kilka przerw w kompilacji z powodu braku wersji produktu lub wersji głównych. Typowe przerwy:
- Żadne moduły
hidl_interface
zawierająceproduct_specific: true
nie będą dostępne dla modułów systemowych. Aby to naprawić, zastąpproduct_specific: true
kodemsystem_ext_specific: true
. - W modułach może brakować wersji produktu wymaganej przez moduły produktów. Aby rozwiązać ten problem, udostępnij ten moduł na partycji
product
, ustawiającproduct_available: true
, lub przenieś moduł do partycjiproduct
, ustawiającproduct_specific: true
.
- Żadne moduły
Rozwiąż błędy kompilacji i upewnij się, że kompilacja urządzenia zakończyła się sukcesem.
Wgraj obraz i sprawdź, czy podczas uruchamiania i w dziennikach nie występują błędy czasu działania.
- Jeśli tag
linker
z logu przypadku testowego zawiera komunikatCANNOT LINK EXECUTABLE
, oznacza to, że w pliku Make brakuje zależności (i nie został on przechwycony podczas kompilacji). - Aby sprawdzić to w systemie kompilacji, dodaj wymaganą bibliotekę do pola
shared_libs:
lubrequired:
.
- Jeśli tag
Rozwiąż problem z brakami zależności, korzystając z podanych wyżej wskazówek.
Krok 4. Wymuś interfejsy Java
W tym kroku ustawisz PRODUCT_ENFORCE_PRODUCT_PARTITION_INTERFACE := true
, a potem znajdziesz i naprawisz wynikowe błędy kompilacji. Poszukaj 2 konkretnych typów błędów:
Błędy typu linku. Ten błąd wskazuje, że aplikacja zawiera linki do modułów Java, które mają szerszy
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 oznacza, że nie można znaleźć symbolu, ponieważ jest on w ukrytym interfejsie API. Aby rozwiązać ten problem, 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ź działanie środowiska wykonawczego
W tym kroku sprawdzisz, czy środowisko wykonawcze działa prawidłowo. W przypadku aplikacji, które można debugować, możesz monitorować użycie ukrytego interfejsu API, korzystając z pliku dziennika StrictMode.detectNonSdkApiUsage
(generuje on plik dziennika, gdy aplikacja używa ukrytego interfejsu API). Możesz też użyć narzędzia do analizy statycznej veridex, aby uzyskać informacje o typie użycia (linkowaniu lub odbiciu), poziomie ograniczeń i zbiorze wywołań.
Składnia Veridex:
./art/tools/veridex/appcompat.sh --dex-file={apk file}
Przykładowy wynik weryfikacji:
#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;
Szczegółowe informacje o używaniu narzędzia veridex znajdziesz w artykule Testowanie za pomocą narzędzia veridex.
Krok 6. Zaktualizuj plik device.mk
Po naprawieniu wszystkich błędów kompilacji i błędów czasu wykonywania oraz sprawdzeniu, czy zachowanie w czasie wykonywania jest zgodne z oczekiwaniami, ustaw w pliku device.mk
te wartości:
PRODUCT_PRODUCT_VNDK_VERSION := current
PRODUCT_ENFORCE_PRODUCT_PARTITION_INTERFACE := true