Applicare le interfacce di partizione dei prodotti

Android 11 separa la partizione product, rendendola indipendente dalle partizioni system e vendor. Nell'ambito di queste modifiche, ora puoi controllare l'accesso della partizione product alle interfacce native e Java (in modo simile al funzionamento dell'applicazione delle interfacce per le partizioni vendor).

Applica interfacce native

Per attivare l'applicazione dell'interfaccia nativa, imposta PRODUCT_PRODUCT_VNDK_VERSION su current. (La versione viene impostata automaticamente su current quando il livello API di spedizione per la destinazione è superiore a 29.) L'applicazione forzata consente:

  • Moduli nativi nella partizione product da collegare:
    • In modo statico o dinamico ad altri moduli nella partizione product che includono librerie statiche, condivise o di intestazione.
    • In modo dinamico alle librerie VNDK nella partizione system.
  • Librerie JNI negli APK non raggruppati nella partizione product a cui collegarsi librerie in /product/lib o /product/lib64 (oltre alle librerie NDK).

L'applicazione non consente altri collegamenti a partizioni diverse dalla partizione product.

Applicazione forzata del tempo di build (Android.bp)

In Android 11, i moduli di sistema possono creare una variante dell'immagine del prodotto oltre alle varianti dell'immagine principale e del fornitore. Quando l'applicazione dell'interfaccia nativa è abilitata (PRODUCT_PRODUCT_VNDK_VERSION è impostato su current):

  • I moduli nativi nella partizione product si trovano nella variante di prodotto anziché nella variante principale.

  • I moduli con product_available: true nei file Android.bp sono disponibili per la variante del prodotto.

  • Le librerie o i binari che specificano product_specific: true possono collegarsi ad altre librerie che specificano product_specific: true o product_available: true nei relativi file Android.bp.

  • Le librerie VNDK devono avere product_available: true nei file Android.bp in modo che i binari product possano collegarsi alle librerie VNDK.

La seguente tabella riassume le proprietà Android.bp utilizzate per creare varianti dell'immagine.

Proprietà in Android.bp Varianti create
Prima dell'applicazione Dopo l'applicazione
predefinito (nessuno) core
(include /system, /system_ext e /product)
core
(include /system e /system_ext ma non /product)
system_ext_specific: true nucleo nucleo
product_specific: true nucleo prodotto
vendor: true fornitore fornitore
vendor_available: true core, vendor core, vendor
product_available: true N/D core, product
vendor_available: true AND product_available: true N/D core, product, vendor
system_ext_specific: true AND vendor_available: true core, vendor core, vendor
product_specific: true AND vendor_available: true core, vendor prodotto, fornitore

Applicazione forzata al momento della build (Android.mk)

Quando l'applicazione dell'interfaccia nativa è attivata, i moduli nativi installati nella partizione product hanno un tipo di link native:product che può collegarsi solo ad altri moduli native:product o native:vndk. Se provi a collegarti a moduli diversi da questi, il sistema di compilazione genera un errore di controllo del tipo di link.

Applicazione di runtime

Quando l'applicazione dell'interfaccia nativa è attivata, la configurazione del linker per il linker bionic non consente ai processi di sistema di utilizzare le librerie product, creando una sezione product per i processi product che non possono collegarsi a librerie esterne alla partizione product (tuttavia, questi processi possono collegarsi a librerie VNDK). I tentativi di violare la configurazione del collegamento runtime causano l'interruzione del processo e la generazione di un messaggio di errore CANNOT LINK EXECUTABLE.

Applica interfacce Java

Per attivare l'applicazione dell'interfaccia Java, imposta PRODUCT_ENFORCE_PRODUCT_PARTITION_INTERFACE su true. (Il valore viene impostato automaticamente su true quando il livello API di spedizione per la destinazione è maggiore di 29.) Se l'opzione è abilitata, l'applicazione consente o non consente il seguente accesso:

API /system /system_ext /product /vendor /data
API pubblica
@SystemApi
@hide API

Come nella partizione vendor, un'app o una libreria Java nella partizione product può utilizzare solo API pubbliche e di sistema; il collegamento a una libreria che utilizza API nascoste non è consentito. Questa limitazione include il collegamento in fase di compilazione e la reflection in fase di runtime.

Applicazione forzata in fase di build

In fase di compilazione, Make e Soong verificano che i moduli Java nella partizione product non utilizzino API nascoste controllando i campi platform_apis e sdk_version. Il sdk_version delle app nella partizione product deve essere compilato con current, system_current o la versione numerica dell'API e il campo platform_apis deve essere vuoto.

Applicazione di runtime

Android Runtime verifica che le app nella partizione product non utilizzino API nascoste, inclusa la reflection. Per i dettagli, consulta Limitazioni alle interfacce non SDK.

Attivare l'applicazione dell'interfaccia del prodotto

Segui i passaggi descritti in questa sezione per attivare l'applicazione dell'interfaccia del prodotto.

Passaggio Attività Obbligatorio
1 Definisci il tuo makefile di sistema che specifica i pacchetti per la partizione system, quindi imposta il controllo dei requisiti del percorso degli artefatti in device.mk (per impedire l'installazione di moduli non di sistema nella partizione system). N
2 Esegui la pulizia della lista consentita. N
3 Applica interfacce native e identifica errori di collegamento di runtime (può essere eseguito in parallelo con l'applicazione Java). Y
4 Applica le interfacce Java e verifica il comportamento del runtime (può essere eseguito in parallelo con l'applicazione nativa). Y
5 Controlla i comportamenti del runtime. Y
6 Aggiornamento di device.mk con l'applicazione dell'interfaccia del prodotto. Y

Passaggio 1: crea il makefile e attiva il controllo del percorso dell'artefatto

In questo passaggio, definisci il makefile system.

  1. Crea un makefile che definisca i pacchetti per la partizione system. Ad esempio, crea un file oem_system.mk con i seguenti contenuti:

    $(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. Nel file device.mk, eredita il makefile comune per la partizione system e attiva il controllo dei requisiti del percorso dell'artefatto. Ad esempio:

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

Informazioni sui requisiti del percorso dell'artefatto

Quando PRODUCT_ENFORCE_ARTIFACT_PATH_REQUIREMENTS è impostato su true o strict, il sistema di compilazione impedisce l'installazione dei pacchetti definiti in altri makefile nei percorsi definiti in require-artifacts-in-path e impedisce l'installazione degli artefatti dei pacchetti definiti nel makefile corrente al di fuori dei percorsi definiti in require-artifacts-in-path.

Nell'esempio precedente, con PRODUCT_ENFORCE_ARTIFACT_PATH_REQUIREMENTS impostato su strict, i makefile esterni a oem_system.mk non possono includere moduli installati nella partizione root o system. Per includere questi moduli, devi definirli nel file oem_system.mk stesso o in un makefile incluso. I tentativi di installare moduli in percorsi non consentiti causano interruzioni della build. Per correggere le interruzioni, procedi in uno dei seguenti modi:

  • Opzione 1: includi il modulo di sistema nei makefile inclusi in oem_system.mk. In questo modo, il requisito del percorso dell'artefatto viene soddisfatto (poiché i moduli ora esistono in un makefile incluso) e quindi consente l'installazione nel set di percorsi in "require-artifacts-in-path".

  • Opzione 2: installa i moduli nella partizione system_ext o product (e non installarli nella partizione system).

  • Opzione 3: aggiungi moduli al PRODUCT_ARTIFACT_PATH_REQUIREMENT_ALLOWED_LIST. Elenca i moduli consentiti da installare.

Passaggio 2: svuota la lista consentita

In questo passaggio, rendi PRODUCT_ARTIFACT_PATH_REQUIREMENT_ALLOWED_LIST vuoto in modo che tutti i dispositivi che condividono oem_system.mk possano condividere anche una singola immagine system. Per svuotare l'elenco consentito, sposta i moduli nell'elenco nella partizione system_ext o product oppure aggiungili a system per creare file. Questo passaggio è facoltativo perché la definizione di un'immagine system comune non è necessaria per attivare l'applicazione dell'interfaccia del prodotto. Tuttavia, svuotare la lista consentita è utile per definire il confine system con system_ext.

Passaggio 3: applica le interfacce native

In questo passaggio, imposta PRODUCT_PRODUCT_VNDK_VERSION := current, quindi cerca gli errori di compilazione e runtime e risolvili. Per controllare l'avvio e i log del dispositivo e trovare e correggere gli errori di collegamento in fase di runtime:

  1. Imposta PRODUCT_PRODUCT_VNDK_VERSION := current.

  2. Crea il dispositivo e cerca eventuali errori di build. È probabile che si verifichino alcuni errori di build per le varianti di prodotto o le varianti principali mancanti. Le pause più comuni includono:

    • Qualsiasi modulo hidl_interface che ha product_specific: true non sarà disponibile per i moduli di sistema. Per risolvere il problema, sostituisci product_specific: true con system_ext_specific: true.
    • Nei moduli potrebbe mancare la variante del prodotto richiesta per i moduli del prodotto. Per risolvere il problema, rendi disponibile il modulo per la partizione product impostando product_available: true o sposta il modulo nella partizione product impostando product_specific: true.
  3. Risolvi gli errori di build e assicurati che la build del dispositivo venga eseguita correttamente.

  4. Carica l'immagine e cerca errori di runtime nell'avvio e nei log del dispositivo.

    • Se il tag linker del log di uno scenario di test mostra un messaggio CANNOT LINK EXECUTABLE, il file make non contiene una dipendenza (e non è stato acquisito in fase di compilazione).
    • Per verificarlo dal sistema di compilazione, aggiungi la libreria richiesta al campo shared_libs: o required:.
  5. Risolvi le dipendenze mancanti seguendo le indicazioni riportate sopra.

Passaggio 4: applica le interfacce Java

In questo passaggio, imposta PRODUCT_ENFORCE_PRODUCT_PARTITION_INTERFACE := true, quindi trova e correggi gli errori di build risultanti. Cerca due tipi specifici di errori:

  • Errori relativi al tipo di collegamento. Questo errore indica che un'app si collega a moduli Java che hanno un sdk_version più ampio. Per risolvere il problema, puoi ampliare l'sdk_version dell'app o limitare l'sdk_version della libreria. Errore di esempio:

    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.
    
  • Errori di simboli. Questo errore indica che non è possibile trovare un simbolo perché si trova in un'API nascosta. Per risolvere il problema, utilizza un'API visibile (non nascosta) o trova un'alternativa. Errore di esempio:

    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
    

Passaggio 5: controlla i comportamenti di runtime

In questo passaggio, verifichi che i comportamenti di runtime siano quelli previsti. Per le app di cui è possibile eseguire il debug, puoi monitorare l'utilizzo di API nascoste tramite log utilizzando StrictMode.detectNonSdkApiUsage (che genera un log quando l'app utilizza un'API nascosta). In alternativa, puoi utilizzare lo strumento di analisi statica veridex per ottenere il tipo di utilizzo (collegamento o riflessione), il livello di restrizione e lo stack di chiamate.

  • Sintassi di Veridex:

    ./art/tools/veridex/appcompat.sh --dex-file={apk file}
  • Risultato di esempio di 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;
    

Per informazioni dettagliate sull'utilizzo di veridex, consulta Testare utilizzando lo strumento veridex.

Passaggio 6: aggiorna device.mk

Dopo aver corretto tutti gli errori di build e di runtime e aver verificato che i comportamenti di runtime siano quelli previsti, imposta quanto segue in device.mk:

  • PRODUCT_PRODUCT_VNDK_VERSION := current
  • PRODUCT_ENFORCE_PRODUCT_PARTITION_INTERFACE := true