La piattaforma Android contiene molti file XML per l'archiviazione dei dati di configurazione (ad esempio, la configurazione audio). Molti file XML si trovano nella partizione vendor
, ma vengono letti nella partizione system
. In questo caso, lo schema
del file XML funge da interfaccia tra le due partizioni e pertanto
lo schema deve essere specificato in modo esplicito e deve evolvere in modo compatibile con le versioni precedenti.
Prima di Android 10, la piattaforma non forniva
meccanismi per richiedere la specifica e l'utilizzo dello schema XML o per impedire
modifiche incompatibili nello schema. Android 10 fornisce
questo meccanismo, chiamato API schema file di configurazione. Questo meccanismo è costituito da uno strumento
chiamato xsdc
e da una regola di build chiamata xsd_config
.
Lo strumento xsdc
è un compilatore di documenti dello schema XML (XSD). Analizza un file XSD
che descrive lo schema di un file XML e genera codice Java e C++. Il codice
generato analizza i file XML conformi allo schema XSD in una struttura ad albero di
oggetti, ognuno dei quali modella un tag XML. Gli attributi XML sono modellati come campi
degli oggetti.
La regola di compilazione xsd_config
integra lo strumento xsdc
nel sistema di compilazione.
Per un determinato file di input XSD, la regola di compilazione genera librerie Java e C++. Puoi collegare le librerie ai moduli in cui vengono letti e utilizzati i file XML conformi allo schema XSD. Puoi utilizzare la regola di compilazione per i tuoi file XML utilizzati
nelle partizioni system
e vendor
.
API Build Config File Schema
Questa sezione descrive come creare l'API Config File Schema.
Configura la regola di build xsd_config in Android.bp
La regola di compilazione xsd_config
genera il codice del parser con lo strumento xsdc
. La proprietà package_name
della regola di build
xsd_config
determina il nome del pacchetto del
codice Java generato.
Esempio di regola di build xsd_config
in Android.bp
:
xsd_config {
name: "hal_manifest",
srcs: ["hal_manifest.xsd"],
package_name: "hal.manifest",
}
Esempio di struttura di directory:
├── Android.bp
├── api
│ ├── current.txt
│ ├── last_current.txt
│ ├── last_removed.txt
│ └── removed.txt
└── hal_manifest.xsd
Il sistema di compilazione genera un elenco di API utilizzando il codice Java generato e lo confronta con l'API. Questo controllo API viene aggiunto a DroidCore ed eseguito alle m -j
.
Crea file di elenchi API
I controlli API richiedono file di elenchi API nel codice sorgente.
Gli elenchi di file dell'API includono:
current.txt
eremoved.txt
verificano se le API vengono modificate confrontandole con i file API generati in fase di compilazione.last_current.txt
elast_removed.txt
controllano se le API sono compatibili con le versioni precedenti confrontandole con i file API.
Per creare i file degli elenchi API:
- Crea file di elenchi vuoti.
- Esegui il comando
make update-api
.
Utilizzare il codice del parser generato
Per utilizzare il codice Java generato, aggiungi :
come prefisso al nome del modulo xsd_config
nella proprietà Java srcs
. Il pacchetto del codice Java generato è lo stesso della proprietà package_name
.
java_library {
name: "vintf_test_java",
srcs: [
"srcs/**/*.java"
":hal_manifest"
],
}
Per utilizzare il codice C++ generato, aggiungi il nome del modulo xsd_config
alle proprietà
generated_sources
e generated_headers
. Aggiungi libxml2
a
static_libs
o shared_libs
, poiché libxml2
è obbligatorio nel codice del parser generato. Lo spazio dei nomi del codice C++ generato è uguale alla proprietà package_name
. Ad esempio, se
il nome del modulo xsd_config
è hal.manifest
, lo spazio dei nomi è
hal::manifest
.
cc_library{
name: "vintf_test_cpp",
srcs: ["main.cpp"],
generated_sources: ["hal_manifest"],
generated_headers: ["hal_manifest"],
shared_libs: ["libxml2"],
}
Utilizzare il parser
Per utilizzare il codice del parser Java, utilizza il metodo XmlParser#read
o
read{class-name}
per restituire la classe dell'elemento
radice. L'analisi viene eseguita in questo momento.
import hal.manifest.*;
…
class HalInfo {
public String name;
public String format;
public String optional;
…
}
void readHalManifestFromXml(File file) {
…
try (InputStream str = new BufferedInputStream(new FileInputStream(file))) {
Manifest manifest = XmlParser.read(str);
for (Hal hal : manifest.getHal()) {
HalInfo halinfo;
HalInfo.name = hal.getName();
HalInfo.format = hal.getFormat();
HalInfo.optional = hal.getOptional();
…
}
}
…
}
Per utilizzare il codice del parser C++, includi prima il file di intestazione. Il nome del file di intestazione è il nome del pacchetto con i punti (.) convertiti in trattini bassi (_).
Quindi utilizza il metodo read
o read{class-name}
per restituire
la classe dell'elemento radice. L'analisi viene eseguita in questo momento. Il valore restituito è
un std::optional<>
.
include "hal_manifest.h"
…
using namespace hal::manifest
struct HalInfo {
public std::string name;
public std::string format;
public std::string optional;
…
};
void readHalManifestFromXml(std::string file_name) {
…
Manifest manifest = *read(file_name.c_str());
for (Hal hal : manifest.getHal()) {
struct HalInfo halinfo;
HalInfo.name = hal.getName();
HalInfo.format = hal.getFormat();
HalInfo.optional = hal.getOptional();
…
}
…
}
Tutte le API fornite per utilizzare il parser si trovano in api/current.txt
. Per
uniformità, tutti i nomi di elementi e attributi vengono convertiti in camel case (ad
esempio, ElementName
) e utilizzati come variabile, metodo e
nome della classe corrispondenti. La classe dell'elemento radice analizzato può essere ottenuta utilizzando la funzione read{class-name}
. Se è presente un solo elemento
radice, il nome della funzione è read
. Il valore di un attributo o
sottoelemento analizzato può essere ottenuto utilizzando la funzione
get{variable-name}
.
Genera codice del parser
Nella maggior parte dei casi, non è necessario eseguire xsdc
direttamente. Utilizza invece la regola di build xsd_config
, come descritto in Configurazione della regola di build xsd_config in Android.bp. Questa
sezione spiega l'interfaccia a riga di comando xsdc
, solo per completezza. Questa
informazione potrebbe essere utile per il debug.
Devi fornire allo strumento xsdc
il percorso del file XSD e un pacchetto. Il
pacchetto è un nome di pacchetto nel codice Java e uno spazio dei nomi nel codice C++. Le opzioni
per determinare se il codice generato è Java o C sono -j
o -c
,
rispettivamente. L'opzione -o
è il percorso della directory di output.
usage: xsdc path/to/xsd_file.xsd [-c] [-j] [-o <arg>] [-p]
-c,--cpp Generate C++ code.
-j,--java Generate Java code.
-o,--outDir <arg> Out Directory
-p,--package Package name of the generated java file. file name of
generated C++ file and header
Comando di esempio:
$ xsdc audio_policy_configuration.xsd -p audio.policy -j