Android 플랫폼에는 구성 데이터 저장을 위한 다수의 XML 파일이 포함되어 있습니다(예: 오디오 구성). 대부분의 XML 파일은 vendor
파티션에 있지만 읽기는 system
파티션에서 이루어집니다. 이 경우 XML 파일의 스키마가 두 파티션의 인터페이스로 기능합니다. 따라서 스키마는 명시적으로 지정되어야 하며 이전 버전과의 호환이 가능한 방식으로 진화해야 합니다.
Android 10 이전에는 플랫폼에서 XML 스키마 지정 및 사용을 요구하거나 스키마에서 호환되지 않는 변경사항을 방지하기 위한 메커니즘을 제공하지 않았습니다. Android 10에서는 이러한 메커니즘을 제공하며, 이를 Config File Schema API라고 부릅니다. 이 메커니즘은 xsdc
라는 도구와 xsd_config
라는 빌드 규칙으로 구성됩니다.
xsdc
도구는 XML 스키마 문서(XSD) 컴파일러입니다. 이 도구는 XML 파일의 스키마를 설명하는 XSD 파일을 파싱하고 자바 및 C++ 코드를 생성합니다. 생성된 코드는 XSD 스키마와 일치하는 XML 파일을 객체의 트리에 파싱합니다. 각 객체는 XML 태그를 모델링합니다. XML 속성은 객체의 필드로 모델링됩니다.
xsd_config
빌드 규칙은 xsdc
도구를 빌드 시스템에 통합합니다.
XSD 입력 파일의 경우 빌드 규칙에 의해 자바 및 C++ 라이브러리가 생성됩니다. 라이브러리는 XSD와 일치하는 XML 파일이 판독 및 사용되는 모듈에 연결할 수 있습니다. 빌드 규칙은 system
및 vendor
파티션에 사용되는 자체 XML 파일에 사용할 수 있습니다.
Config File Schema API 빌드
이 섹션에서는 Config File Schema API를 빌드하는 방법에 대해 설명합니다.
Android.bp에서 xsd_config 빌드 규칙 생성
xsd_config
빌드 규칙은 xsdc
도구로 파서 코드를 생성합니다. xsd_config
빌드 규칙의 package_name
속성은 생성된 자바 코드의 패키지 이름을 결정합니다.
Android.bp
의 xsd_config
빌드 규칙 예시:
xsd_config {
name: "hal_manifest",
srcs: ["hal_manifest.xsd"],
package_name: "hal.manifest",
}
디렉터리 구조 예시:
├── Android.bp
├── api
│ ├── current.txt
│ ├── last_current.txt
│ ├── last_removed.txt
│ └── removed.txt
└── hal_manifest.xsd
빌드 시스템은 생성된 자바 코드를 사용하여 API 목록을 생성한 후 이를 토대로 API를 검사합니다. 이 API 검사는 DroidCore에 추가되며 m -j
에서 실행됩니다.
API 목록 파일 생성
API 검사를 진행하려면 소스 코드에 API 목록 파일이 있어야 합니다.
API 목록 파일에는 다음이 포함됩니다.
current.txt
및removed.txt
는 빌드 시간에 생성된 API 파일과 비교하여 API가 변경되었는지 확인합니다.last_current.txt
및last_removed.txt
는 API 파일과 비교하여 API가 이전 버전과 호환되는지 확인합니다.
API 목록 파일 생성 방법:
- 빈 목록 파일을 만듭니다.
- 명령어
make update-api
를 실행합니다.
생성된 파서 코드 사용
생성된 자바 코드를 사용하려면 :
를 자바 srcs
속성의 xsd_config
모듈 이름에 접두사로 추가합니다. 생성된 자바 코드의 패키지는 package_name
속성과 동일합니다.
java_library {
name: "vintf_test_java",
srcs: [
"srcs/**/*.java"
":hal_manifest"
],
}
생성된 C++ 코드를 사용하려면 xsd_config
모듈 이름을 generated_sources
및 generated_headers
속성에 추가합니다. 그런 다음 libxml2
가 생성된 파서 코드에 필요하므로 libxml2
를 static_libs
또는 shared_libs
에 추가합니다. 생성된 C++ 코드의 네임스페이스는 package_name
속성과 동일합니다. 예를 들어 xsd_config
모듈 이름이 hal.manifest
인 경우 네임스페이스는 hal::manifest
입니다.
cc_library{
name: "vintf_test_cpp",
srcs: ["main.cpp"],
generated_sources: ["hal_manifest"],
generated_headers: ["hal_manifest"],
shared_libs: ["libxml2"],
}
파서 사용
자바 파서 코드를 사용하려면 XmlParser#read
또는 read{class-name}
메서드를 사용하여 루트 요소의 클래스를 반환해야 합니다. 파싱은 이 시점에 발생합니다.
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();
…
}
}
…
}
C++ 파서 코드를 사용하려면 먼저 헤더 파일을 포함해야 합니다. 헤더 파일의 이름은 마침표(.)가 밑줄(_)로 변환된 패키지 이름입니다.
그런 다음 read
또는 read{class-name}
메서드를 사용하여 루트 요소의 클래스를 반환합니다. 파싱은 이 시점에 발생합니다. 반환 값은 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();
…
}
…
}
파서를 사용하도록 제공된 모든 API는 api/current.txt
에 있습니다. 일관성을 위해 모든 요소와 속성 이름은 카멜 표기법(예: ElementName
)으로 변환되며 해당하는 변수, 메서드와 클래스 이름으로 사용됩니다. 파싱된 루트 요소의 클래스는 read{class-name}
함수를 사용하여 가져올 수 있습니다. 루트 요소가 하나인 경우의 함수 이름은 read
입니다. 파싱된 하위 요소나 속성의 값은 get{variable-name}
함수를 사용하여 가져올 수 있습니다.
파서 코드 생성
대부분의 경우 xsdc
를 직접 실행할 필요는 없습니다. Android.bp에서 xsd_config 빌드 규칙 구성에 설명된 것처럼 xsd_config
빌드 규칙을 대신 사용하세요. 이 섹션에서는 완전성을 기하기 위해 xsdc
명령줄 인터페이스에 대해 설명합니다. 이는 디버깅에 유용할 수 있습니다.
XSD 파일 경로와 패키지를 xsdc
도구에 제공해야 합니다. 패키지는 자바 코드의 패키지 이름, C++ 코드의 네임스페이스입니다. 생성된 코드가 자바인지 C인지 파악하기 위한 옵션은 각각 -j
또는 -c
입니다. -o
옵션은 출력 디렉터리의 경로입니다.
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
명령어 예:
$ xsdc audio_policy_configuration.xsd -p audio.policy -j