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 forzata dell'interfaccia per le partizioni vendor).

Applicare forzatamente le interfacce native

Per attivare l'applicazione forzata 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 è maggiore di 29.) L'applicazione forzata consente:

  • I moduli nativi nella partizione product da collegare:
    • Staticamente o dinamicamente ad altri moduli nella partizione product che includono librerie statiche, condivise o di intestazione.
    • Dinamicamente alle librerie VNDK nella partizione system.
  • Le librerie JNI negli APK separati nella partizione product da collegare alle librerie in /product/lib o /product/lib64 (oltre alle librerie NDK).

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

Applicazione forzata in fase di compilazione (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 forzata dell'interfaccia nativa è attivata (PRODUCT_PRODUCT_VNDK_VERSION è impostato su current):

  • I moduli nativi nella partizione product si trovano nella variante del 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 file binari che specificano product_specific: true possono essere collegati ad altre librerie che specificano product_specific: true o product_available: true nei file Android.bp.

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

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

Proprietà in Android.bp Varianti create
Prima dell'applicazione forzata Dopo l'applicazione forzata
default (nessuna) core
(include /system, /system_ext e /product)
core
(include /system e /system_ext, ma non /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 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 product, vendor

Applicazione forzata in fase di build (Android.mk)

Quando l'applicazione forzata dell'interfaccia nativa è attivata, i moduli nativi installati nella product partizione hanno un tipo di link native:product che può essere collegato solo a altri native:product o native:vndk moduli. Se tenti di collegare altri moduli, il sistema di compilazione genera un errore di controllo del tipo di link.

Applicazione forzata in fase di runtime

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

Applicare forzatamente le interfacce Java

Per attivare l'applicazione forzata 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.) Quando è attivata, l'applicazione forzata consente o non consente il seguente accesso:

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

Come nella partizione vendor, un'app o una libreria Java nella partizione product può utilizzare solo le API pubbliche e di sistema; non è consentito il collegamento a una libreria che utilizza API nascoste. Questa limitazione include il collegamento in fase di build 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, mentre il campo platform_apis deve essere vuoto.

Applicazione forzata in fase di runtime

Il runtime di Android verifica che le app nella partizione product non utilizzino API nascoste, inclusa la reflection. Per maggiori dettagli, consulta Limitazioni delle interfacce non SDK.

Attivare l'applicazione forzata dell'interfaccia del prodotto

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

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

Passaggio 1: crea il makefile e attiva il controllo del percorso degli artefatti

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 degli artefatti. 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 degli artefatti

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 i moduli nei percorsi non consentiti causano interruzioni della build. Per risolvere le interruzioni, esegui una delle seguenti operazioni:

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

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

  • Opzione 3: aggiungi i moduli a PRODUCT_ARTIFACT_PATH_REQUIREMENT_ALLOWED_LIST. In questo modo vengono elencati 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 la lista consentita, sposta tutti i moduli nell'elenco nella system_ext o product partizione oppure aggiungili ai system make files. Questo passaggio è facoltativo perché la definizione di un'immagine system comune non è obbligatoria per attivare l'applicazione forzata dell'interfaccia del prodotto. Tuttavia, svuotare la lista consentita è utile per definire il system limite con system_ext.

Passaggio 3: applica forzatamente le interfacce native

In questo passaggio, imposta PRODUCT_PRODUCT_VNDK_VERSION := current, quindi cerca e risolvi gli errori di build e di runtime. Per controllare l'avvio e i log del dispositivo e trovare e correggere gli errori di link di runtime:

  1. Imposta PRODUCT_PRODUCT_VNDK_VERSION := current.

  2. Crea il dispositivo e cerca gli errori di build. È probabile che si verifichino alcune interruzioni della build per le varianti del prodotto o le varianti principali mancanti. Le interruzioni comuni includono:

    • Qualsiasi modulo hidl_interface con product_specific: true non sarà disponibile per i moduli di sistema. Per risolvere il problema, sostituisci product_specific: true con system_ext_specific: true.
    • I moduli potrebbero non avere la variante del prodotto richiesta per i moduli del prodotto. Per risolvere il problema, rendi il modulo disponibile per la partizione product impostando product_available: true oppure 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. Flash l'immagine e cerca gli errori di runtime nell'avvio e nei log del dispositivo.

    • Se il tag linker di un log di uno scenario di test mostra un messaggio CANNOT LINK EXECUTABLE, significa che nel file make manca una dipendenza (e non è stata acquisita in fase di tempo di compilazione).
    • Per controllarlo 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 forzatamente le interfacce Java

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

  • Errori di tipo di link. Questo errore indica che un'app è collegata a moduli Java con un sdk_version più ampio. Per risolvere il problema, puoi ampliare l'sdk_version dell'app o limitare l'sdk_version della libreria. Esempio di errore:

    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. Esempio di errore:

    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, verifica che i comportamenti di runtime siano quelli previsti. Per le app di cui è possibile eseguire il debug, puoi monitorare l'utilizzo delle API nascoste tramite il 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 reflection), il livello di limitazione e lo stack di chiamate.

  • Sintassi di Veridex:

    ./art/tools/veridex/appcompat.sh --dex-file={apk file}
  • Esempio di risultato 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 maggiori dettagli 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