compiler_service
OHOS SystemAbility (SA ID 5300) that exposes AOT compilation as an IPC service, allowing other system components to trigger AOT compilation of JS/TS bundles on-device. Primary Language: C++
Design
1.1 Service Architecture
The service follows OHOS's SystemAbility pattern:
Client App / System (installd, BMS, etc.)
│ IPC (Binder)
▼
AotCompilerInterfaceProxy ──IPC──▶ AotCompilerInterfaceStub
│
▼
AotCompilerService (SA lifecycle)
│
▼
AotCompilerImpl (singleton)
│ fork()
▼
Child process runs ark_aot_compiler / ark_aot
│
▼
.an file + .ai file + code signature
1.2 IPC Interface
The service exposes 4 IPC methods via IAotCompilerInterface:
| Method | Code | Purpose |
|---|---|---|
AotCompiler(args, sigData) |
COMMAND_AOT_COMPILER |
Trigger AOT compilation, returns code signature |
StopAotCompiler() |
COMMAND_STOP_AOT_COMPILER |
Kill running compilation child process |
GetAOTVersion(sigData) |
COMMAND_GET_AOT_VERSION |
Query current AOT file version |
NeedReCompile(oldVersion, sigData) |
COMMAND_NEED_RE_COMPILE |
Check if re-compilation is needed for given version |
1.3 Compilation Flow (EcmascriptAotCompiler)
The main compilation flow in AotCompilerImpl::EcmascriptAotCompiler:
1. PrepareArgsHandler ── check allowAotCompiler_, create AOTArgsHandler, run parser Check()
2. ShouldPreCreateOutputFiles ── decide if .an/.ai need pre-creation
3. PreCreateAotFiles ── create output dir + .an file (with FD) + .ai file
chown/chmod to bundleUid, FD managed by CompilationCleanupGuard
4. ForkAndExecute ── fork child process
├── Parent: HapVerifyInParent (verify bundle name + appIdentifier via libhapverify.z.so)
│ then ExecuteInParentProcess (waitpid, collect exit status)
└── Child: PrepareChildProcess (clear FD_CLOEXEC on guard fd, pass --an-fd)
DropCapabilities (setuid/setgid to bundleUid, drop all caps)
ExecuteInChildProcess (execv ark_aot_compiler / ark_aot)
5. HandlePostCompilation
├── SendSysEvent (HiSysEvent reporting)
├── AOTLocalCodeSign (SignLocalCodeByFd preferred, fallback to SignLocalCode)
├── SetAotSecurityLabels (xattr on .an + .ai)
└── guard.Dismiss() (close fd, keep .an/.ai files)
1.4 Argument Parsing (Factory Pattern)
AOTArgsParserFactory::GetParser() selects a parser based on request args:
AOTArgsParserFactory::GetParser(args, isEnableStaticCompiler)
├── isSysComp=true && static compiler enabled
│ └── StaticFrameworkAOTArgsParser → /system/bin/ark_aot
├── moduleArkTSMode="dynamic"
│ └── AOTArgsParser → /system/bin/ark_aot_compiler
├── moduleArkTSMode="static"|"hybrid" && static compiler enabled
│ └── StaticAOTArgsParser → /system/bin/ark_aot
└── otherwise → std::nullopt (compilation rejected)
Parser types and their FD argument names:
| Parser | Type Enum | Executable | FD Arg |
|---|---|---|---|
AOTArgsParser |
DYNAMIC_AOT |
/system/bin/ark_aot_compiler |
--an-fd |
StaticAOTArgsParser |
STATIC_AOT |
/system/bin/ark_aot |
--paoc-an-fd |
StaticFrameworkAOTArgsParser |
FRAMEWORK_STATIC_AOT |
/system/bin/ark_aot |
--paoc-an-fd |
Dynamic AOT args: --aot-file, --target-compiler-mode, --compiler-pkg-info (JSON), --compiler-external-pkg-info (JSON), --compiler-device-state, --compiler-baseline-pgo, --compiler-opt-bc-range, --compiler-thermal-level.
Static AOT args: --boot-panda-files (from /system/framework/bootpath.json), --paoc-output, --paoc-location, --paoc-panda-files, --paoc-use-profile:path=<profile>, --compiler-regex (filter), plus defaults (--load-runtimes=ets, --paoc-generate-symbols=true, etc.).
1.5 Security & Validation
AotArgsVerify provides comprehensive argument validation:
- Path traversal: rejects
..,../,/../in all file paths - Ark cache directory: validates paths under
/data/app/el1/public/aot_compiler/ark_cache/<bundleName>/or/data/service/el1/public/for-all-app/framework_ark_cache/ - Bundle UID/GID: must be >= 10000 for app bundles and host-private shared HSP AOT
- ABC offset/size: validates
abcOffset + abcSize <= HAP file size - Compile mode: must be "partial" or "full"
- ArkTS mode: must be "dynamic", "static", or "hybrid"
- HAP verification: dynamically loads
libhapverify.z.soto verify bundleName and appIdentifier against HAP content (parent process only, for dynamic AOT) - Code sign path validation:
CheckCodeSignArkCacheFilePathresolves realpath and validates prefix
1.6 Runtime Governance (Event Listeners)
Three system event listeners registered in OnStart(), unregistered in OnStop():
| Listener | Event | Behavior |
|---|---|---|
PowerDisconnectedListener |
COMMON_EVENT_POWER_DISCONNECTED |
Stop compiler, pause 30s, then allow |
ScreenStatusSubscriber |
COMMON_EVENT_SCREEN_ON |
Stop compiler, pause 40s, then allow |
ThermalMgrListener |
COMMON_EVENT_THERMAL_LEVEL_CHANGED |
Level >= 2 → pause; < 2 → allow |
Pause/allow is controlled by allowAotCompiler_ atomic bool checked at compilation entry.
1.7 SA Lifecycle & Auto-Unload
- SA registered with
run-on-create: false(lazy load) - After each IPC call, schedules auto-unload via
DelayUnloadTask(180s delay) - Before each IPC call, cancels pending unload via
RemoveUnloadTask - Client loads SA on demand via
SystemAbilityManager::LoadSystemAbilitywithAotCompilerLoadCallback - Client waits for SA load with 6s timeout (
loadSaCondition_)
1.8 Code Signing Flow
1. SA process creates .an file with open() → FD kept in anFd_
2. FD passed to child via fork (FD_CLOEXEC cleared) → child writes AOT output
3. After compilation, SA signs via:
a. SignLocalCodeByFd(anFd_) — preferred (FD-based)
b. SignLocalCode(path) — fallback (path-based, for static/framework or FD failure)
4. Security labels (xattr) set on .an and .ai files
Key design decisions:
- Compilation runs in a forked child process to isolate crashes and resource limits.
- FD-based code signing avoids path-based attacks and works with the file descriptor directly.
- HAP verification (
CheckBundleNameAndAppIdentifier) runs in the parent process concurrently with child compilation, and kills the child if verification fails. - Static interpreter compilation uses dedicated parsers and
/system/bin/ark_aot. - AOT arguments are validated through
AOTArgsHandler::Handle()→parser->Check()+parser->Parse()before fork. - The IPC contract is defined in
iaot_compiler_interface.h; proxy and stub are ininterface/. - SA auto-unloads after 180s of inactivity to save system resources.
Key Files
| File | Role |
|---|---|
src/aot_compiler_impl.cpp |
Core logic: fork child, run compiler, code sign, collect result |
src/aot_compiler_service.cpp |
SA lifecycle (OnStart/OnStop), event listener registration, auto-unload |
src/aot_compiler_client.cpp |
Client-side IPC wrapper, SA lazy loading, death recipient |
interface/iaot_compiler_interface.h |
IPC interface definition (4 methods) |
interface/aot_compiler_interface_stub.cpp |
Server-side IPC message dispatch (4 commands) |
interface/aot_compiler_interface_proxy.cpp |
Client-side IPC message construction |
include/aot_compiler_args.h |
AotCompilerArgs struct (Parcelable) + HspModuleInfo struct |
src/aot_args_handler.cpp |
Argument parsing via Factory pattern (Dynamic/Static/Framework parsers) |
include/aot_args_handler.h |
AOTArgsHandler, AOTArgsParserBase, parser classes, AOTArgsParserFactory |
src/aot_args_verify.cpp |
Comprehensive argument validation (path traversal, bundle checks, HAP verify) |
include/aot_args_verify.h |
AotArgsVerify class, AotPkgInfo/AotPkgVerifyInfo/ExternalPkgVerifyInfo structs |
include/aot_compiler_constants.h |
All constants, enums (AotParserType, BundleType, AotTriggerType, RetStatusOfCompiler), error code mappings |
include/aot_compiler_error_utils.h |
Error code enum (ERR_OK..INVALID_ERR_CODE) + AotCompilerErrorUtil |
include/aot_args_list.h |
Whitelisted argument sets (aotArgsList, staticAOTArgsList, default arg vectors) |
src/aot_compiler_load_callback.cpp |
SA load callback (delegates to AotCompilerClient) |
src/power_disconnected_listener.cpp |
Power disconnected event → HandlePowerDisconnected() |
src/screen_status_listener.cpp |
Screen on event → HandleScreenOn() |
src/thermal_mgr_listener.cpp |
Thermal level changed event → HandleThermalLevelChanged() |
sa_profile/5300.json |
SA registration (SA ID 5300, process "compiler_service", libpath "libcompiler_service.z.so") |
BUILD.gn |
Build targets: libcompiler_service (SA so), config files, SA profile |
AotCompilerArgs Structure
The IPC argument struct (include/aot_compiler_args.h) carries:
| Group | Fields |
|---|---|
| Identity | isSysComp, compileMode (partial/full), moduleArkTSMode (dynamic/static/hybrid) |
| Package info | bundleName, moduleName, appIdentifier, bundleUid, bundleGid, processUid |
| File paths | hapPath, abcPath, anFileName, outputPath, arkProfilePath, sysCompPath, pgoDir |
| ABC info | abcOffset, abcLength |
| Compilation options | optBCRangeList, isScreenOff, isEncryptedBundle, isEnableBaselinePgo |
| Extra ints | bundleType, triggerType, staticAndHybridModuleCnt |
| External packages | hspModules (vector of HspModuleInfo: bundleName, moduleName, hapPath, moduleArkTSMode, offset, length) |
Serialization is grouped into 7 sections: Identity → PackageInfo → FilePaths → AbcInfo → CompilationOptions → ExtraInts → HspModules.
Error Codes
Defined in aot_compiler_error_utils.h:
| Code | Value | Meaning |
|---|---|---|
ERR_OK |
0 | Success |
ERR_OK_NO_AOT_FILE |
10001 | No AOT file generated (no AP file, version check skip) |
ERR_AOT_COMPILER_PARAM_FAILED |
10002 | Invalid arguments |
ERR_AOT_COMPILER_CONNECT_FAILED |
10003 | Failed to connect to SA |
ERR_AOT_COMPILER_SIGNATURE_FAILED |
10004 | Code signing failed |
ERR_AOT_COMPILER_SIGNATURE_DISABLE |
10005 | Code signing disabled |
ERR_AOT_COMPILER_CALL_FAILED |
10006 | Compiler execution failed |
ERR_AOT_COMPILER_STOP_FAILED |
10007 | Failed to stop compiler |
ERR_AOT_COMPILER_CALL_CRASH |
10008 | Child process crashed (non-SIGKILL signal) |
ERR_AOT_COMPILER_CALL_CANCELLED |
10009 | Compilation cancelled (thermal/pause, or framework .an already exists) |
Child process exit codes are mapped via RetInfoOfCompiler in aot_compiler_constants.h. SIGKILL → ERR_AOT_COMPILER_CALL_CANCELLED, other signals → ERR_AOT_COMPILER_CALL_CRASH.
Configuration Files
| File | Install Location | Purpose |
|---|---|---|
compiler_service.cfg |
/system/etc/init/ |
SA process init config |
ark_aot_compiler.cfg |
/system/etc/init/ |
Compiler child process init config |
system_framework_aot_enable_list.conf |
/system/etc/ark/ |
Framework AOT enable list |
static_app_install_aot_enable_list.conf |
/system/etc/ark/ |
Static app install AOT enable list |
Build
Full OHOS tree only (depends on samgr, ipc, code_signature, common_event_service, etc.):
./build.sh --product-name <product-name> --build-target compiler_service:compiler_service
Conditional build flags:
CODE_SIGN_ENABLE— enabled whensecurity_code_signaturepart is presentENABLE_COMPILER_SERVICE_GET_PARAMETER— enabled for standard OHOS builds (allows reading system parameters likeark.aot.enable_static_compiler,ark.aot.compiler_an_file_max_size,ark.aot.code_comment.enable)
Tests
Full OHOS tree only:
./build.sh --product-name <product-name> --build-target compiler_service/test:compiler_service_unittest
./build.sh --product-name <product-name> --build-target compiler_service/test:compiler_service_fuzztest
- Unit tests:
test/unittest/— aotcompilerservice_unit, aotcompilerproxy_unit, aotcompilerclient_unit, aotcompilerstub_unit, aotcompilererrorutils_unit, aotcompilerimpl_unit, aotcompilerargshandler_unit, aotargsverify_unit - Fuzz tests:
test/fuzztest/— compilerinterfacestub_fuzzer, aotcompilerargsprepare_fuzzer - Shared test config:
test/compiler_service_test.gni
How to Modify
Add a new IPC method:
- Add the method declaration to
interface/iaot_compiler_interface.h - Add the proxy implementation in
interface/aot_compiler_interface_proxy.cpp - Add the stub dispatch case in
interface/aot_compiler_interface_stub.cpp - Implement the logic in
src/aot_compiler_impl.cpp - Wire through
src/aot_compiler_service.cpp - Expose on client side in
src/aot_compiler_client.cpp - Add unit test in
test/unittest/
Add a new system event listener:
- Create listener class in
include/andsrc/(followpower_disconnected_listenerpattern) - Register/unregister in
AotCompilerService::OnStart()/OnStop() - Wire the callback to
AotCompilerImpl(addHandle*method)
Add a new argument to AotCompilerArgs:
- Add field to
include/aot_compiler_args.hstruct - Add serialization in the appropriate
Write*/Read*helper method - Update
AotArgsVerifyif validation is needed - Update relevant parser in
aot_args_handler.cpp
Add a new parser type:
- Add to
AotParserTypeenum inaot_compiler_constants.h - Create parser class inheriting
AOTArgsParserBaseinaot_args_handler.h/cpp - Add to
AOTArgsParserFactory::GetParser() - Add validation branch in
AOTArgsParserBase::Check() - Add FD arg name via
GetFdArgName()override
Boundaries
- IPC contract changes must be synchronized across
interface/,include/, andsrc/. - Keep
sa_profile/5300.jsonconsistent with the service process/lib name and SA ID. - This module only orchestrates compilation — actual compiler logic lives in
ecmascript/compiler/. - Service lifecycle/listener logic stays in
src/; do not mix test-only code into production sources. AotArgsVerify::CheckBundleNameAndAppIdentifierdynamically loadslibhapverify.z.so— this dependency must be available on device.- Error codes in
aot_compiler_constants.h::RetInfoOfCompilermust stay in sync withets_runtime/ecmascript/aot_compiler.cppexit codes. AotTriggerTypeandBundleTypeenum values must match BMS definitions.