Produktpartitionsoberflächen erzwingen

Android 11 entbündelt die Partition product und ist somit unabhängig von den Partitionen system und vendor. Im Rahmen dieser Änderungen können Sie jetzt den Zugriff der product-Partition auf native und Java-Schnittstellen steuern. Das funktioniert ähnlich wie die Erzwingung von Schnittstellen für vendor-Partitionen.

Native Oberflächen erzwingen

Wenn Sie die Durchsetzung der nativen Benutzeroberfläche aktivieren möchten, setzen Sie PRODUCT_PRODUCT_VNDK_VERSION auf current. Die Version wird automatisch auf current gesetzt, wenn die API-Version für das Ziel höher als 29 ist. Durch die Erzwingung ist Folgendes möglich:

  • Native Module in der Partition product, die verknüpft werden sollen:
    • Statisch oder dynamisch an andere Module in der product-Partition, die statische, freigegebene 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 sollen (zusätzlich zu den NDK-Bibliotheken)

Die Erzwingung lässt außer der Partition product keine anderen Links zu Partitionen zu.

Durchsetzung zur Buildzeit (Android.bp)

In Android 11 können Systemmodule zusätzlich zu Kern- und Anbieterbildvarianten eine Produktbildvariante erstellen. Wenn die Erzwingung der nativen Benutzeroberfläche aktiviert ist (PRODUCT_PRODUCT_VNDK_VERSION auf current gesetzt ist):

  • Native Module in der product-Partition befinden sich in der Produktvariante und nicht in der Kernvariante.

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

  • Bibliotheken oder Binärdateien, die product_specific: true angeben, können mit anderen Bibliotheken verknüpft werden, die product_specific: true oder product_available: true in ihren Android.bp-Dateien angeben.

  • VNDK-Bibliotheken müssen product_available: true in ihren Android.bp-Dateien enthalten, 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 Image-Varianten verwendet werden.

Properties in Android.bp Erstellte Varianten
Vor der Erzwingung Nach der Durchsetzung
Standardeinstellung (kein) 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 core, vendor Kern, Anbieter
product_available: true Kern, Produkt
vendor_available: true UND product_available: true Kern, Produkt, Anbieter
system_ext_specific: true UND vendor_available: true Kern, Anbieter core, vendor
product_specific: true UND vendor_available: true Kern, Anbieter Produkt, Anbieter

Erzwingung zur Buildzeit (Android.mk)

Wenn die Erzwingung der nativen Schnittstelle 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, eine Verknüpfung mit anderen Modulen herzustellen, generiert das Build-System einen Fehler bei der Linktypprüfung.

Laufzeitdurchsetzung

Wenn die Erzwingung der nativen Schnittstelle aktiviert ist, erlaubt die Linker-Konfiguration für den Bionic-Linker Systemprozessen nicht, product-Bibliotheken zu verwenden. Es 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, gegen die Laufzeitverknüpfungskonfiguration zu verstoßen, führen dazu, dass der Vorgang fehlschlägt und eine CANNOT LINK EXECUTABLE-Fehlermeldung generiert wird.

Java-Schnittstellen erzwingen

Wenn Sie die Durchsetzung der Java-Oberfläche 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 über 29 liegt. Wenn die Erzwingung aktiviert ist, wird der folgende Zugriff zugelassen oder verhindert:

API /system /system_ext /product /vendor /data
Public API
@SystemApi
@hide-API

Wie in der Partition vendor dürfen Apps oder Java-Bibliotheken in der Partition product nur öffentliche und System-APIs verwenden. Verknüpfungen mit einer Bibliothek, die versteckte APIs verwendet, sind nicht zulässig. Diese Einschränkung umfasst die Verknüpfung zum Build-Zeitpunkt und die Reflexion während der Laufzeit.

Durchsetzung zur Buildzeit

Zum Zeitpunkt der Build-Phase prüfen Make und Soong, ob Java-Module in der Partition product keine versteckten APIs verwenden. Dazu werden die Felder platform_apis und sdk_version geprüft. Die sdk_version der Anwendungen in der Partition product muss mit current, system_current oder der numerischen Version der API ausgefüllt werden und das Feld platform_apis muss leer sein.

Laufzeitdurchsetzung

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

Erzwingung der Produktoberfläche aktivieren

Führen Sie die Schritte in diesem Abschnitt aus, um die Erzwingung der Produktoberfläche zu aktivieren.

Schritt Aufgabe Erforderlich
1 Definieren Sie ein eigenes System-Makefile, in dem die Pakete für die Partition system angegeben sind, und legen Sie dann die Prüfung der Pfadvoraussetzung für Artefakte in der device.mk fest, um zu verhindern, dass nicht systemeigene Module in der Partition system installiert werden. N
2 Bereinigen Sie die Zulassungsliste. N
3 Native Schnittstellen erzwingen und Laufzeitverknüpfungsfehler identifizieren (kann parallel zur Java-Erzwigung ausgeführt werden). J
4 Java-Schnittstellen erzwingen und Laufzeitverhalten prüfen (kann parallel zur nativen Erzwingung ausgeführt werden) J
5 Prüfen Sie das Laufzeitverhalten. J
6 Aktualisieren Sie device.mk mit der Erzwingung der Produktoberfläche. J

Schritt 1: Makefile erstellen und Artefaktpfadprüfung 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 Makefile für die Partition system und aktivieren Sie die Prüfung der Anforderungen für 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 Pfad des Artefakts

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

Im obigen Beispiel, wobei PRODUCT_ENFORCE_ARTIFACT_PATH_REQUIREMENTS auf strict gesetzt ist, können Makefiles außerhalb von oem_system.mk keine Module enthalten, die in der Partition root oder system installiert sind. Wenn du diese Module einbinden möchtest, musst du sie entweder in der Datei oem_system.mk selbst oder in einem enthaltenen Makefile definieren. Versuche, Module in nicht zulässigen Pfaden zu installieren, führen zu Build-Unterbrechungen. So korrigieren Sie Pausen:

  • Option 1:Fügen Sie das Systemmodul in die Makefiles in oem_system.mk ein. Dadurch wird die Anforderung an den Artefaktpfad erfüllt (da die Module jetzt in einem enthaltenen Makefile vorhanden sind) und die Installation in der Gruppe von Pfaden in „require-artifacts-in-path“ möglich.

  • Option 2:Installieren Sie Module in der Partition system_ext oder product, aber nicht in der Partition system.

  • Option 3:Dem PRODUCT_ARTIFACT_PATH_REQUIREMENT_ALLOWED_LIST Module hinzufügen Hier sind die Module aufgeführt, die installiert werden dürfen.

Schritt 2: Zugelassene Liste leeren

In diesem Schritt machen Sie das PRODUCT_ARTIFACT_PATH_REQUIREMENT_ALLOWED_LIST leer, damit alle Geräte, die oem_system.mk freigeben, auch ein einzelnes system-Bild freigeben können. Zum Leeren der Liste der zulässigen Module verschieben Sie alle Module in der Liste in die Partition system_ext oder product oder fügen sie den Erstellungsdateien system hinzu. Dieser Schritt ist optional, da das Definieren eines gemeinsamen system-Images nicht erforderlich ist, um die Erzwingung der Produktoberfläche zu aktivieren. Es ist jedoch hilfreich, die Zulassungsliste zu leeren, um die system-Grenze mit system_ext zu definieren.

Schritt 3: Native Oberflächen erzwingen

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

  1. Legen Sie PRODUCT_PRODUCT_VNDK_VERSION := current fest.

  2. Erstellen Sie das Gerät und suchen Sie nach Build-Fehlern. Sie werden wahrscheinlich einige Build-Unterbrechungen für fehlende Produktvarianten oder Kernvarianten sehen. Zu den häufigsten Unterbrechungen gehören:

    • hidl_interface-Module mit product_specific: true sind für Systemmodule nicht verfügbar. Ersetzen Sie product_specific: true durch system_ext_specific: true, um das Problem zu beheben.
    • In den Modulen fehlt möglicherweise die für Produktmodule erforderliche Produktvariante. Um das Problem zu beheben, stellen Sie das Modul für die product-Partition zur Verfügung, 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 prüfen Sie, ob das Gerät erfolgreich erstellt werden kann.

  4. Flashen Sie das Image und suchen Sie im Boot-Vorgang und in den Protokollen des Geräts nach Laufzeitfehlern.

    • Wenn im linker-Tag aus einem Testfallprotokoll eine CANNOT LINK EXECUTABLE-Meldung angezeigt wird, fehlt der Makefile eine Abhängigkeit und sie wurde beim Build nicht erfasst.
    • Wenn Sie die Funktion ü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 gegebenen Anleitung.

Schritt 4: Java-Schnittstellen erzwingen

In diesem Schritt legen Sie PRODUCT_ENFORCE_PRODUCT_PARTITION_INTERFACE := true fest und suchen dann nach den resultierenden Buildfehlern, die Sie beheben. Achten Sie auf zwei bestimmte Arten von Fehlern:

  • Fehler beim Linktyp Dieser Fehler gibt an, dass eine App auf Java-Module verweist, die eine breitere sdk_version haben. Sie können das Problem beheben, indem 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, da es sich in einer verborgenen API befindet. Verwenden Sie eine sichtbare (nicht ausgeblendete) API oder suchen Sie nach einer Alternative. 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 das Laufzeitverhalten erwartungsgemäß ist. Bei Apps, die debugfähig sind, können Sie die Nutzung versteckter APIs mithilfe von StrictMode.detectNonSdkApiUsage überwachen. Dadurch wird ein Log generiert, wenn die App eine versteckte API verwendet. Alternativ können Sie das statische Analysetool veridex verwenden, um die Art der Nutzung (Verknüpfung oder Reflexion), die Einschränkungsebene und den Aufrufstack 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 im Hilfeartikel Mit dem Veridex-Tool testen.

Schritt 6: device.mk aktualisieren

Nachdem Sie alle Build- und Laufzeitfehler behoben und geprüft haben, ob das Laufzeitverhalten den Erwartungen entspricht, legen Sie in device.mk Folgendes fest:

  • PRODUCT_PRODUCT_VNDK_VERSION := current
  • PRODUCT_ENFORCE_PRODUCT_PARTITION_INTERFACE := true