W Androidzie 11 partycja product jest oddzielona od partycji system i vendor. W ramach tych zmian możesz teraz kontrolować dostęp partycji product do interfejsów natywnych i Java (podobnie jak w przypadku wymuszania interfejsów w partycjach vendor).
Wymuszanie interfejsów natywnych
Aby włączyć wymuszanie interfejsów natywnych, ustaw PRODUCT_PRODUCT_VNDK_VERSION na current. (Gdy poziom interfejsu API wysyłki dla miejsca docelowego jest większy niż 29, wersja jest automatycznie ustawiana na current.) Wymuszanie umożliwia:
- łączenie modułów natywnych w partycji
product:- statyczne lub dynamiczne z innymi modułami w partycji
product, które zawierają statyczne, współdzielone lub nagłówkowe biblioteki; - dynamiczne z bibliotekami VNDK w partycji
system.
- statyczne lub dynamiczne z innymi modułami w partycji
- łączenie bibliotek JNI w oddzielnych plikach APK w partycji
productz bibliotekami w/product/liblub/product/lib64(oprócz bibliotek NDK).
Wymuszanie nie zezwala na inne połączenia z partycjami innymi niż product.
Wymuszanie podczas tworzenia kompilacji (Android.bp)
W Androidzie 11 moduły systemowe mogą tworzyć wariant obrazu produktu oprócz wariantów obrazu podstawowego i dostawcy. Gdy włączone jest wymuszanie interfejsów natywnych (PRODUCT_PRODUCT_VNDK_VERSION jest ustawione na current):
moduły natywne w partycji
productznajdują się w wariancie produktu, a nie w wariancie podstawowym;moduły z
product_available: truew plikachAndroid.bpsą dostępne dla wariantu produktu;biblioteki lub pliki binarne, które określają
product_specific: true, mogą łączyć się z innymi bibliotekami, które określająproduct_specific: truelubproduct_available: truew plikachAndroid.bp;biblioteki VNDK muszą mieć
product_available: truew plikachAndroid.bpaby pliki binarneproductmogły łączyć się z bibliotekami VNDK.
W tabeli poniżej znajdziesz podsumowanie właściwości Android.bp używanych do tworzenia wariantów obrazu.
| Właściwości w Android.bp | Utworzone warianty | |
|---|---|---|
| Przed wymuszeniem | Po wymuszeniu | |
| default (none) | core
(includes /system, /system_ext and
/product) |
core
(includes /system and /system_ext but not
/product) |
system_ext_specific: true |
core | core |
product_specific: true |
core | product |
vendor: true |
vendor | vendor |
vendor_available: true |
core, vendor | core, vendor |
product_available: true |
Nie dotyczy | core, product |
vendor_available: true AND product_available:
true |
Nie dotyczy | core, product, vendor |
system_ext_specific: true AND vendor_available:
true |
core, vendor | core, vendor |
product_specific: true AND vendor_available:
true |
core, vendor | product, vendor |
Wymuszanie podczas tworzenia kompilacji (Android.mk)
Gdy włączone jest wymuszanie interfejsów natywnych, moduły natywne zainstalowane w partycji
product mają typ połączenia native:product, który może łączyć się tylko z
innymi native:product lub native:vndk modułami. Próba połączenia z innymi modułami spowoduje wygenerowanie przez system kompilacji błędu sprawdzania typu połączenia.
Wymuszanie podczas działania
Gdy włączone jest wymuszanie interfejsów natywnych, konfiguracja linkera dla linkera bionic nie pozwala procesom systemowym na używanie bibliotek product, tworząc sekcję product dla procesów product, które nie mogą łączyć się z bibliotekami poza partycją product (jednak takie procesy mogą łączyć się z bibliotekami VNDK). Próby naruszenia konfiguracji połączenia podczas działania powodują niepowodzenie procesu i wygenerowanie komunikatu o błędzie CANNOT LINK EXECUTABLE.
Wymuszanie interfejsów Java
Aby włączyć wymuszanie interfejsów Java, ustaw PRODUCT_ENFORCE_PRODUCT_PARTITION_INTERFACE na true. (Gdy poziom interfejsu API wysyłki dla miejsca docelowego jest większy niż 29, wartość jest automatycznie ustawiana na true.) Gdy ta opcja jest włączona, wymuszanie zezwala na dostęp lub go zabrania:
| 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. Nie można łączyć się z biblioteką, która używa ukrytych interfejsów API. To ograniczenie obejmuje łączenie podczas tworzenia kompilacji i odbicie podczas działania.
Wymuszanie podczas tworzenia kompilacji
Podczas tworzenia kompilacji Make i Soong sprawdzają, czy moduły Java w partycji product nie używają ukrytych interfejsów API, sprawdzając pola platform_apis i sdk_version. Pole sdk_version aplikacji w partycji product musi
być wypełnione wartością current, system_current lub numeryczną wersją interfejsu API, a
pole platform_apis musi być puste.
Wymuszanie podczas działania
Środowisko wykonawcze Androida sprawdza, czy aplikacje w partycji product nie używają ukrytych interfejsów API, w tym odbicia. Więcej informacji znajdziesz w artykule Ograniczenia dotyczące
interfejsów innych niż SDK.
Włączanie wymuszania interfejsu produktu
Aby włączyć wymuszanie interfejsu produktu, wykonaj czynności opisane w tej sekcji.
| Krok | Zadanie | Wymagane |
|---|---|---|
| 1 | Zdefiniuj własny plik makefile systemu, który określa pakiety dla
system partycji, a następnie ustaw sprawdzanie wymagań dotyczących ścieżki artefaktów
w device.mk (aby uniemożliwić instalowanie modułów innych niż systemowe
w system partycji). |
N |
| 2 | Zwolnij miejsce na liście dozwolonych. | N |
| 3 | Wymuś interfejsy natywne i zidentyfikuj błędy połączeń podczas działania (można uruchomić równolegle z wymuszaniem Java). | y |
| 4 | Wymuś interfejsy Java i sprawdź zachowanie podczas działania (można uruchomić równolegle z wymuszaniem natywnym). | y |
| 5 | Sprawdź zachowania podczas działania. | y |
| 6 | Zaktualizuj device.mk o wymuszanie interfejsu produktu. |
y |
Krok 1. Utwórz plik makefile i włącz sprawdzanie ścieżki artefaktu
W tym kroku zdefiniujesz plik makefile system.
Utwórz plik makefile, który określa pakiety dla partycji
system. Na przykład utwórz plikoem_system.mkz tymi treściami:$(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.mkodziedzicz wspólny plik makefile dla partycjisystemi 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 PRODUCT_ENFORCE_ARTIFACT_PATH_REQUIREMENTS jest ustawione na true lub strict, system kompilacji uniemożliwia instalowanie pakietów zdefiniowanych w innych plikach makefile w ścieżkach zdefiniowanych w require-artifacts-in-path oraz uniemożliwia instalowanie artefaktów pakietó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 w
partycji root lub system. Aby uwzględnić te moduły, musisz zdefiniować je 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ć te przerwy, wykonaj jedną z tych czynności:
Opcja 1. Uwzględnij moduł systemowy w plikach makefile dołączonych do
oem_system.mk. Dzięki temu wymaganie dotyczące ścieżki artefaktu zostanie spełnione (ponieważ moduły znajdują się teraz w dołączonym pliku makefile), co umożliwi instalację w zbiorze ścieżek w `require-artifacts-in-path`.Opcja 2: Zainstaluj moduły w partycji
system_extlubproduct(i nie instaluj modułów w 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 opróżnisz PRODUCT_ARTIFACT_PATH_REQUIREMENT_ALLOWED_LIST, aby wszystkie urządzenia korzystające z oem_system.mk mogły też korzystać z jednego obrazu system. Aby opróżnić listę dozwolonych, przenieś wszystkie moduły z listy do partycji
system_ext lub product albo dodaj je do plików makefile system. Ten krok jest opcjonalny, ponieważ zdefiniowanie wspólnego obrazu system nie jest wymagane do włączenia wymuszania interfejsu produktu. Opróżnienie listy dozwolonych jest jednak
przydatne do zdefiniowania granicy system za pomocą system_ext.
Krok 3. Wymuś interfejsy natywne
W tym kroku ustawisz PRODUCT_PRODUCT_VNDK_VERSION := current, a następnie poszukasz błędów kompilacji i błędów podczas działania oraz je rozwiążesz. Aby sprawdzić uruchamianie urządzenia i logi oraz znaleźć i naprawić błędy połączeń podczas działania:
Ustaw
PRODUCT_PRODUCT_VNDK_VERSION := current.Utwórz kompilację urządzenia i poszukaj błędów kompilacji. Prawdopodobnie zobaczysz kilka przerw w kompilacji spowodowanych brakiem wariantów produktu lub wariantów podstawowych. Typowe przerwy to:
- Każdy moduł
hidl_interface, który maproduct_specific: true, nie będzie dostępny dla modułów systemowych. Aby rozwiązać ten problem, zastąpproduct_specific: truewartościąsystem_ext_specific: true. - W modułach może brakować wariantu produktu wymaganego przez moduły produktu. Aby rozwiązać ten problem, udostępnij ten moduł partycji
productprzez ustawienieproduct_available: truelub przenieś moduł do partycjiproductprzez ustawienieproduct_specific: true.
- Każdy moduł
Rozwiąż błędy kompilacji i upewnij się, że kompilacja urządzenia zakończyła się powodzeniem.
Flashuj obraz i poszukaj błędów środowiska wykonawczego w logach i podczas uruchamiania urządzenia.
- Jeśli tag
linkerz logu przypadku testowego zawiera komunikatCANNOT LINK EXECUTABLE, w pliku makefile brakuje zależności (i nie została ona przechwycona podczas tworzenia kompilacji). - Aby sprawdzić to w systemie kompilacji, dodaj wymaganą bibliotekę do pola
shared_libs:lubrequired:.
- Jeśli tag
Rozwiąż problem z brakującymi zależnościami, korzystając z podanych wyżej wskazówek.
Krok 4. Wymuś interfejsy Java
W tym kroku ustawisz PRODUCT_ENFORCE_PRODUCT_PARTITION_INTERFACE := true, a następnie znajdziesz i naprawisz wynikowe błędy kompilacji. Poszukaj 2 konkretnych typów błędów:
Błędy typu połączenia. Ten błąd oznacza, że aplikacja łączy się z modułami Java, które mają szerszy zakres
sdk_version. Aby rozwiązać ten problem, możesz rozszerzyćsdk_versionaplikacji lub ograniczyćsdk_versionbiblioteki. 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ż znajduje się 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ź zachowania podczas działania
W tym kroku sprawdzisz, czy zachowania podczas działania są zgodne z oczekiwaniami. W przypadku aplikacji, które można debugować, możesz monitorować użycie ukrytych interfejsów API za pomocą dziennika, używając StrictMode.detectNonSdkApiUsage (który generuje dziennik, 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 (łączenie lub odbicie),
poziomie ograniczeń i stosie wywołań.
Składnia veridex:
./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;
Więcej informacji o użyciu veridex znajdziesz w artykule Testowanie za pomocą narzędzia veridex.
Krok 6. Zaktualizuj device.mk
Po naprawieniu wszystkich błędów kompilacji i błędów podczas działania oraz sprawdzeniu, czy zachowania podczas działania są zgodne z oczekiwaniami, ustaw w device.mk te wartości:
PRODUCT_PRODUCT_VNDK_VERSION := currentPRODUCT_ENFORCE_PRODUCT_PARTITION_INTERFACE := true