Produktaufteilungsoberflächen erzwingen

In Android 11 wird die product-Partition entkoppelt, sodass sie unabhängig von den Partitionen system und vendor ist. Im Rahmen dieser Änderungen können Sie jetzt den Zugriff der product-Partition auf native und Java-Schnittstellen steuern. Das funktioniert ähnlich wie die Schnittstellenerzwingung für vendor-Partitionen.

Native Schnittstellen erzwingen

Wenn Sie die Durchsetzung der nativen Schnittstelle aktivieren möchten, setzen Sie PRODUCT_PRODUCT_VNDK_VERSION auf current. Die Version wird automatisch auf current festgelegt, wenn der Versand-API-Level für das Ziel höher als 29 ist. Durch die Durchsetzung sind folgende Aktionen möglich:

  • Native Module in der Partition product, die verknüpft werden sollen:
    • Statisch oder dynamisch zu anderen Modulen in der product-Partition, die statische, gemeinsam genutzte oder Header-Bibliotheken enthalten.
    • Dynamisch zu VNDK-Bibliotheken in der system-Partition.
  • JNI-Bibliotheken in nicht gebündelten APKs in der Partition product, die mit Bibliotheken in /product/lib oder /product/lib64 verknüpft werden (zusätzlich zu den NDK-Bibliotheken).

Die Erzwingung erlaubt keine anderen Links zu Partitionen als zur product-Partition.

Erzwingung der Build-Dauer (Android.bp)

In Android 11 können Systemmodule zusätzlich zu den Core- und Vendor-Bildvarianten eine Produktbildvariante erstellen. Wenn die Erzwingung nativer Schnittstellen aktiviert ist (PRODUCT_PRODUCT_VNDK_VERSION ist auf current gesetzt):

  • Native Module in der Partition product sind in der Produktvariante anstelle der Core-Variante enthalten.

  • Module mit product_available: true in ihren Android.bp-Dateien sind für die Produktvariante verfügbar.

  • Bibliotheken oder Binärdateien, in denen product_specific: true angegeben ist, können mit anderen Bibliotheken verknüpft werden, in deren Android.bp-Dateien product_specific: true oder product_available: true angegeben ist.

  • VNDK-Bibliotheken müssen product_available: true in ihren Android.bp-Dateien haben, damit product-Binärdateien mit VNDK-Bibliotheken verknüpft werden können.

In der folgenden Tabelle sind die Android.bp-Attribute zusammengefasst, die zum Erstellen von Bildvarianten verwendet werden.

Attribute in Android.bp Erstellte Varianten
Vor der Durchsetzung Nach der Durchsetzung
Standardeinstellung (keine) core
(einschließlich /system, /system_ext und /product)
core
(einschließlich /system und /system_ext, aber nicht /product)
system_ext_specific: true Kern Kern
product_specific: true Kern Produkt
vendor: true Anbieter Anbieter
vendor_available: true Kern, Anbieter Kern, Anbieter
product_available: true Kernprodukt
vendor_available: true UND product_available: true core, product, vendor
system_ext_specific: true UND vendor_available: true Kern, Anbieter Kern, Anbieter
product_specific: true UND vendor_available: true Kern, Anbieter Produkt, Anbieter

Erzwingung der Build-Dauer (Android.mk)

Wenn die Erzwingung nativer Schnittstellen aktiviert ist, haben native Module, die in der Partition product installiert sind, den Linktyp native:product, der nur mit anderen native:product- oder native:vndk-Modulen verknüpft werden kann. Wenn Sie versuchen, Links zu anderen Modulen als diesen zu erstellen, generiert das Build-System einen Fehler bei der Überprüfung des Linktyps.

Laufzeitdurchsetzung

Wenn die Erzwingung nativer Schnittstellen aktiviert ist, lässt die Linker-Konfiguration für den Bionic-Linker nicht zu, dass Systemprozesse product-Bibliotheken verwenden. Dadurch wird ein product-Abschnitt für die product-Prozesse erstellt, die nicht mit Bibliotheken außerhalb der product-Partition verknüpft werden können. Solche Prozesse können jedoch mit VNDK-Bibliotheken verknüpft werden. Versuche, die Laufzeitlinkkonfiguration zu verletzen, führen dazu, dass der Prozess fehlschlägt und eine CANNOT LINK EXECUTABLE-Fehlermeldung generiert wird.

Java-Schnittstellen erzwingen

Wenn Sie die Durchsetzung der Java-Schnittstelle aktivieren möchten, setzen Sie PRODUCT_ENFORCE_PRODUCT_PARTITION_INTERFACE auf true. Der Wert wird automatisch auf true gesetzt, wenn die Versand-API-Ebene für das Ziel höher als 29 ist. Wenn die Erzwingung aktiviert ist, wird der folgende Zugriff zugelassen oder nicht:

API /system /system_ext /product /vendor /data
Öffentliche API
@SystemApi
@hide API

Wie in der Partition vendor darf eine App oder Java-Bibliothek in der Partition product nur öffentliche und System-APIs verwenden. Das Verknüpfen mit einer Bibliothek, die verborgene APIs verwendet, ist nicht zulässig. Diese Einschränkung umfasst das Verknüpfen zur Build-Zeit und die Reflektion zur Laufzeit.

Durchsetzung der Build-Zeit

Zur Build-Zeit prüfen Make und Soong, ob Java-Module in der Partition product verborgene APIs verwenden. Dazu werden die Felder platform_apis und sdk_version geprüft. Das Feld sdk_version von Apps in der Partition product muss mit current, system_current oder der numerischen Version der API gefüllt sein und das Feld platform_apis muss leer sein.

Laufzeitdurchsetzung

Die Android-Laufzeit prüft, ob Apps in der Partition product keine verborgenen APIs verwenden, einschließlich Reflection. Weitere Informationen finden Sie unter Einschränkungen für Nicht-SDK-Schnittstellen.

Erzwingung der Produktschnittstelle aktivieren

Führen Sie die Schritte in diesem Abschnitt aus, um die Durchsetzung der Produktschnittstelle zu aktivieren.

Schritt Aufgabe Erforderlich
1 Definieren Sie Ihr eigenes System-Makefile, in dem die Pakete für die system-Partition angegeben werden. Legen Sie dann die Anforderung für den Artefaktpfad in der device.mk fest, um zu verhindern, dass Nicht-Systemmodule in der system-Partition installiert werden. N
2 Bereinigen Sie die Zulassungsliste. N
3 Native Schnittstellen erzwingen und Linkfehler zur Laufzeit erkennen (kann parallel zur Java-Durchsetzung ausgeführt werden). J
4 Java-Schnittstellen erzwingen und Laufzeitverhalten prüfen (kann parallel zur nativen Erzwingung ausgeführt werden). J
5 Laufzeitverhalten prüfen J
6 device.mk mit der Durchsetzung der Produktschnittstelle aktualisieren J

Schritt 1: Makefile erstellen und Prüfung des Artefaktpfads aktivieren

In diesem Schritt definieren Sie das system-Makefile.

  1. Erstellen Sie ein Makefile, in dem die Pakete für die system-Partition definiert werden. Erstellen Sie beispielsweise eine oem_system.mk-Datei mit folgendem Inhalt:

    $(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),)
    
  2. Übernehmen Sie in der Datei device.mk das gemeinsame Makefiles für die Partition system und aktivieren Sie die Prüfung der Anforderungen an den Artefaktpfad. Beispiel:

    $(call inherit-product, $(SRC_TARGET_DIR)/product/oem_system.mk)
    
    # Enable artifact path requirements checking
    PRODUCT_ENFORCE_ARTIFACT_PATH_REQUIREMENTS := strict
    

Anforderungen an den Artefaktpfad

Wenn PRODUCT_ENFORCE_ARTIFACT_PATH_REQUIREMENTS auf true oder strict festgelegt ist, verhindert das Build-System, dass Pakete, die in anderen Makefiles definiert sind, in den in require-artifacts-in-path definierten Pfaden installiert werden und verhindert, dass Pakete, die im aktuellen Makefile definiert sind, Artefakte außerhalb der in require-artifacts-in-path definierten Pfade installieren.

Wenn im obigen Beispiel PRODUCT_ENFORCE_ARTIFACT_PATH_REQUIREMENTS auf strict festgelegt ist, können Makefiles außerhalb von oem_system.mk keine Module einbinden, die auf der Partition root oder system installiert sind. Wenn Sie diese Module einbinden möchten, müssen Sie sie entweder in der Datei oem_system.mk selbst oder in einer eingebundenen Make-Datei definieren. Versuche, Module in nicht zulässigen Pfaden zu installieren, führen zu Build-Fehlern. Führen Sie einen der folgenden Schritte aus, um das Problem zu beheben:

  • Option 1:Das Systemmodul in die Makefiles einfügen, die in oem_system.mk enthalten sind. Dadurch wird die Anforderung für den Artefaktpfad erfüllt, da die Module jetzt in einer enthaltenen Make-Datei vorhanden sind. Die Installation ist also für die Pfade in „require-artifacts-in-path“ möglich.

  • Option 2:Installieren Sie Module in der Partition system_ext oder product (und nicht in der Partition system).

  • Option 3:Fügen Sie dem PRODUCT_ARTIFACT_PATH_REQUIREMENT_ALLOWED_LIST Module hinzu. Hier werden die zulässigen Module aufgeführt, die installiert werden dürfen.

Schritt 2: Zulassungsliste leeren

In diesem Schritt machen Sie PRODUCT_ARTIFACT_PATH_REQUIREMENT_ALLOWED_LIST leer, damit alle Geräte, die oem_system.mk gemeinsam nutzen, auch ein einzelnes system-Bild teilen können. Wenn Sie die Liste der zulässigen Module leeren möchten, verschieben Sie alle Module in der Liste in die Partition system_ext oder product oder fügen Sie sie den system-Makefiles hinzu. Dieser Schritt ist optional, da kein gemeinsames system-Bild definiert werden muss, um die Erzwingung der Produktoberfläche zu aktivieren. Das Leeren der Zulassungsliste ist jedoch hilfreich, um die system-Grenze mit system_ext zu definieren.

Schritt 3: Native Schnittstellen erzwingen

In diesem Schritt legen Sie PRODUCT_PRODUCT_VNDK_VERSION := current fest, suchen nach Build- und Laufzeitfehlern und beheben diese. So prüfen Sie den Gerätestart und die Logs und beheben Laufzeitlinkfehler:

  1. Legen Sie PRODUCT_PRODUCT_VNDK_VERSION := current fest.

  2. Erstellen Sie das Gerät und suchen Sie nach Build-Fehlern. Wahrscheinlich werden einige Build-Fehler aufgrund fehlender Produktvarianten oder Kernvarianten angezeigt. Häufige Pausen sind:

    • hidl_interface-Module mit product_specific: true sind nicht für Systemmodule verfügbar. Ersetzen Sie product_specific: true durch system_ext_specific: true, um das Problem zu beheben.
    • In Modulen fehlt möglicherweise die für Produktmodule erforderliche Produktvariante. Um das Problem zu beheben, machen Sie das Modul für die product-Partition verfügbar, indem Sie product_available: true festlegen, oder verschieben Sie das Modul in die product-Partition, indem Sie product_specific: true festlegen.
  3. Beheben Sie Build-Fehler und sorgen Sie dafür, dass das Gerät erfolgreich erstellt wird.

  4. Flashen Sie das Image und suchen Sie im Geräte-Bootvorgang und in den Logs nach Laufzeitfehlern.

    • Wenn das linker-Tag aus einem Testlaufprotokoll die Meldung CANNOT LINK EXECUTABLE anzeigt, fehlt in der Make-Datei eine Abhängigkeit (die beim Erstellen nicht erfasst wurde).
    • Wenn Sie sie über das Build-System prüfen möchten, fügen Sie die erforderliche Bibliothek dem Feld shared_libs: oder required: hinzu.
  5. Beheben Sie die fehlenden Abhängigkeiten anhand der oben genannten Anleitung.

Schritt 4: Java-Schnittstellen erzwingen

In diesem Schritt legen Sie PRODUCT_ENFORCE_PRODUCT_PARTITION_INTERFACE := true fest und beheben dann die resultierenden Build-Fehler. Achten Sie auf zwei bestimmte Arten von Fehlern:

  • Fehler bei Linktypen: Dieser Fehler weist darauf hin, dass eine App auf Java-Module verweist, die einen breiteren sdk_version haben. Um das Problem zu beheben, können Sie den sdk_version der App erweitern oder den sdk_version der Bibliothek einschränken. Beispiele für Fehlermeldungen:

    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.
    
  • Symbolfehler: Dieser Fehler weist darauf hin, dass ein Symbol nicht gefunden werden kann, weil es sich in einer verborgenen API befindet. Verwenden Sie eine sichtbare (nicht ausgeblendete) API oder suchen Sie nach einer Alternative, um das Problem zu beheben. Beispiele für Fehlermeldungen:

    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
    

Schritt 5: Laufzeitverhalten prüfen

In diesem Schritt prüfen Sie, ob sich die Laufzeit wie erwartet verhält. Bei Apps, die debugfähig sind, können Sie die Verwendung verborgener APIs mithilfe von StrictMode.detectNonSdkApiUsage protokollieren (wodurch ein Log generiert wird, wenn die App eine verborgene API verwendet). Alternativ können Sie das Tool für statische Analysen veridex verwenden, um den Nutzungstyp (Verknüpfung oder Spiegelung), die Einschränkungsstufe und den Aufrufstapel abzurufen.

  • Veridex-Syntax:

    ./art/tools/veridex/appcompat.sh --dex-file={apk file}
  • Beispiel für ein Veridex-Ergebnis:

    #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;
    

Weitere Informationen zur Verwendung von Veridex finden Sie unter Mit dem Veridex-Tool testen.

Schritt 6: „device.mk“ aktualisieren

Nachdem Sie alle Build- und Laufzeitfehler behoben und überprüft haben, dass das Laufzeitverhalten wie erwartet ist, legen Sie in device.mk Folgendes fest:

  • PRODUCT_PRODUCT_VNDK_VERSION := current
  • PRODUCT_ENFORCE_PRODUCT_PARTITION_INTERFACE := true