Trade Study: Metric Key Set — Android HAL evidence - rdkcentral/rdk-halif-aidl GitHub Wiki
- Type: Evidence sheet, companion to Trade Study: Metric Key Set — how it is carried
- Audience: Anyone checking a claim about what Android HALs do with a list of reportable items
-
Purpose: Every HAL in
hardware/interfacesatandroid-17.0.0_r1that reports a set of named figures, statuses or parameters, sorted by where it keeps the list, with what each frozen version bump carried and which teams changed shape
What this is. Every HAL in hardware/interfaces at android-17.0.0_r1 that reports a set of named figures, statuses or parameters, sorted by where it keeps the list of what can be asked for, with what each frozen version bump carried.
What it covers. Six HALs that type the list into the interface, seven that keep it beside the interface, the size and version history of each, which HALs changed shape between Android 8 and 17, what Android's own guidance says, and two telemetry paths that are not HALs. No argument, no recommendation.
Who it is for. Anyone deciding whether the getMetrics() key set belongs inside the interface or beside it, and wanting to see which Android HALs do which.
Every figure is read from an AOSP tree at android-17.0.0_r1, the current Android release, by the method stated beside it, and every file quoted is linked at that commit. Counts were produced on 2026-09-21.
Every Android 17 HAL is a static interface: methods, parcelables and a .hash frozen per version. The HALs differ in one thing only — whether the list of what can be asked for is part of what freezes.
flowchart LR
subgraph S1["Shape 1 — the list is typed into the interface"]
direction TB
A1["<b>frozen interface vN</b><br/>methods · envelope · <b>the list</b><br/>an enum, or one struct member per figure"]
A2["<b>interface vN+1</b>"]
A1 -->|"one new item"| A2
end
subgraph S2["Shape 2 — the list is beside the interface"]
direction TB
B1["<b>frozen interface vN</b><br/>methods · envelope<br/>selector: int[] · String[] · byte[]"]
B2["<b>the list</b><br/>a header · a schema file ·<br/>a separate package · runtime data"]
B3["the list, revised"]
B1 -.->|"names items from"| B2
B2 -->|"one new item"| B3
end
style A1 fill:#FCF3CF,color:#1a1a1a,stroke:#8a6d1f
style A2 fill:#F5B7B1,color:#1a1a1a,stroke:#922b21
style B1 fill:#FCF3CF,color:#1a1a1a,stroke:#8a6d1f
style B2 fill:#ABEBC6,color:#1a1a1a,stroke:#1e7a4d
style B3 fill:#ABEBC6,color:#1a1a1a,stroke:#1e7a4d
style S1 fill:#FFFDF3,color:#1a1a1a,stroke:#8a6d1f
style S2 fill:#F4FBF6,color:#1a1a1a,stroke:#1e7a4d
Android 17 uses both. Which one a HAL uses tracks three properties of its list:
| Shape 1 — typed in | Shape 2 — beside | |
|---|---|---|
| HALs | TV tuner, TV media quality, health, thermal, sensors, power | power stats, Codec2, camera, vehicle, gralloc, audio core, DRM |
| Size of the list | 21 – 112 items | 146 parameters, 374 camera tags, or unbounded runtime data |
| Who adds to it | Google alone | Google and vendors — each reserves a vendor range or leaves the list to the product |
| When it moves | with the platform release — no HAL here cut more than one version per Android release | whenever the header, schema file or product changes |
| Cost of one new item | one frozen interface version | none to the interface |
| HAL | What the interface declares | Size of the list | Newest frozen version at Android 13 · 14 · 15 · 16 · 17 |
|---|---|---|---|
TV tuner (android.hardware.tv.tuner) |
FrontendStatus[] getStatus(in FrontendStatusType[] statusTypes) — an array of enumerators selects, a union answers |
FrontendStatusType: 42 → 47 → 48 across versions 1 → 2 → 3 |
1 · 2 · 2 · 3 · 3 |
TV media quality (android.hardware.tv.mediaquality) |
getParamCaps(in ParameterName[] paramNames, out ParamCapability[] caps), with getVendorParamCaps(in VendorParameterIdentifier[] names, …) beside it for what vendors add, over a ParcelableHolder
|
ParameterName: 96 → 112 across versions 1 → 2 |
– · – · – · 1 · 2 |
Health (android.hardware.health) |
HealthInfo getHealthInfo() — a parcelable with one member per figure, plus one getter per figure such as getChargeCounterUah()
|
one struct | 1 · 2 · 3 · 4 · 5 |
Thermal (android.hardware.thermal) |
Temperature[] getTemperaturesWithType(in TemperatureType type) |
TemperatureType: 15 → 21 → 21 |
– · 1 · 2 · 3 · 3 |
Sensors (android.hardware.sensors) |
SensorInfo { SensorType type; … } |
SensorType: 43 → 43 → 44 |
1 · 2 · 2 · 3 · 3 |
Power (android.hardware.power) |
setMode(in Mode type, …), setBoost(in Boost type, …)
|
closed enums | 3 · 4 · 5 · 6 · 7 |
The tuner is an AV HAL, and its status read is the typed-in shape at its plainest: an enum array in, typed values out. It also answers capability per item, through getFrontendStatusReadiness(in FrontendStatusType[] statusTypes) returning UNDEFINED, UNAVAILABLE, UNSTABLE, STABLE or UNSUPPORTED for each.
What each version bump carried, where the bump is six added lines or fewer:
| HAL | Bump | Files changed | The whole content of the version |
|---|---|---|---|
| Power | 6 → 7 | 1 of 22 | AUDIO_PERFORMANCE, |
| Power | 2 → 3 | 1 of 5 |
GAME = 15, GAME_LOADING = 16,
|
| Sensors | 2 → 3 | 1 of 8 | MOISTURE_INTRUSION = 43, |
| Power stats | 1 → 2 | 1 of 11 |
CAMERA, — added to its one closed enum |
| Health | 4 → 5 | 2 of 13 |
batteryManufacturer, batteryModelName, batteryVoltageMinDesignUv, FORCE_FULL_CHARGE
|
| Thermal | 2 → 3 | 2 of 9 | one method and one callback |
| TV tuner | 2 → 3 | 4 of 193 | one status type, STANDARD_EXT, with its union member and the enum it returns |
Health cut a version at every Android release from 13 to 17, and versions 3, 4 and 5 each consist of members added to the reporting parcelables.
The tuner's HIDL history shows what the shape costs once a list is frozen and the language cannot extend it. [email protected] froze getStatus(vec<FrontendStatusType>) over 22 status types. Adding 15 more in [email protected] took a second enum, FrontendStatusTypeExt1_1, and a second method beside the first, getStatusExt1_1(vec<FrontendStatusTypeExt1_1>). The AIDL rewrite merged them into one enum of 42.
android.hardware.power.stats measures power. Searching every .aidl file in hardware/interfaces for an interface whose subject is metrics, statistics or telemetry returns this one and nothing else.
PowerEntity[] getPowerEntityInfo();
StateResidencyResult[] getStateResidency(in int[] powerEntityIds);
EnergyConsumer[] getEnergyConsumerInfo();
EnergyConsumerResult[] getEnergyConsumed(in int[] energyConsumerIds);
Channel[] getEnergyMeterInfo();
EnergyMeasurement[] readEnergyMeter(in int[] channelIds);Three lists, three reads. Each list is returned at runtime as { int id; String name; … }; each read names what it wants with an int[] of those ids. Nothing the product measures is a type in the interface, so a product that measures more returns a longer list under the same frozen version.
The package uses both shapes side by side. Its one enum, EnergyConsumerType, classifies a consumer as OTHER, BLUETOOTH, CPU_CLUSTER, DISPLAY, GNSS, MOBILE_RADIO or WIFI, and that enum is the only thing its second version changed: ten of eleven files are byte-identical, and the eleventh gained CAMERA.
Android discovers this list at runtime, where a declared key set derives identifiers ahead of time. Both keep the list out of what freezes. getStateResidency documents EX_ILLEGAL_ARGUMENT for an invalid id, which works because a caller reads the list from the same product before naming anything from it; a caller built against a newer declaration than the product needs NOT_SUPPORTED instead.
| HAL | What the interface declares | Where the list lives | Size, Android 10 → 17 | Frozen interface versions |
|---|---|---|---|---|
Codec2 (android.hardware.media.c2) |
QueryResult query(in int[] indices, in boolean mayBlock). HIDL 1.0 the same, over typedef uint32_t ParamIndex. |
enum C2ParamIndexKind in C2Config.h, in frameworks/av — a different repository from the HAL. Vendors take their own range from TYPE_INDEX_VENDOR_START = 0x00008000. |
109 → 146 |
1 2 — the bump carried one line in IInputSurfaceConnection.aidl; query is unchanged |
Camera (android.hardware.camera.device) |
parcelable CameraMetadata { byte[] metadata; } |
camera/docs/metadata_definitions.xml in system/media: a schema language Google defined, with its own generator producing headers and documentation |
262 → 374 | 1 2 3 4 |
Vehicle (android.hardware.automotive.vehicle) |
VehiclePropValue { int prop; … }; getPropConfigs(in int[] props)
|
VehicleProperty enum in the separate package android.hardware.automotive.vehicle.property
|
— | vehicle 1 2 3 4; property 1 2 3 4 |
Gralloc (IMapper 4.0 and stable-c) |
MetadataType { string name; int64_t value; }; C ABI getStandardMetadata(buffer, int64_t standardMetadataType, …) with listSupportedMetadataTypes()
|
StandardMetadataType.aidl in the separately versioned package android.hardware.graphics.common
|
— |
graphics.common: 1 2 3 4 5 6 7
|
Audio core (android.hardware.audio.core) |
getVendorParameters(in @utf8InCpp String[] ids); VendorParameter { String id; ParcelableHolder ext; }
|
outside the AIDL entirely | — | 1 2 3 4 |
DRM (android.hardware.drm) |
List<DrmMetricGroup> getMetrics(); DrmMetric { String name; … }
|
"The scope and definition of the metrics is defined by the plugin." | — | 1 2 |
Searching the HAL tree for a method that names what it wants with an array of identifiers returns twenty-four. Seven select from a list of this kind — Codec2 query, the three power-stats reads, vehicle getPropConfigs, broadcast radio getParameters(in String[] keys), audio core getVendorParameters — and the rest name runtime objects such as sensor handles, enrolment ids and stream ids.
Gralloc records why its list left the interface, in IMapper.hal:
In order to allow arbitrary vendor defined metadata, we could not use a HIDL enum as the buffer metadata token. Extending a HIDL enum requires a full HIDL extension. We also could not use a simple non-HIDL enum because vendor defined enums from different vendors could collide. […] The standard buffer metadata types are NOT defined as a HIDL enum because it would have required a new IMapper version just to add future standard buffer metadata types. By putting the enum in the stable AIDL (
hardware/interfaces/graphics/common/aidl/android/hardware/graphics/common/StandardMetadataType.aidl), vendors will be able to optionally choose to support future standard buffer metadata types without upgrading HIDL versions.
The list moved out of the interface that carries it, and into another AIDL package rather than into a new definition language. That package, android.hardware.graphics.common, has seven frozen versions, and AOSP's versioning documentation names it: "In Android platform code android.hardware.graphics.common is the biggest example of this type of version upgrade."
No HAL history shows a general migration from one shape to the other. A HAL takes a shape when it is designed, most keep it, and the newest TV HAL took the typed one.
| When | HAL | What happened | Direction |
|---|---|---|---|
| Android 8 → 17 | Health | Typed throughout: HIDL 1.0, 2.0, 2.1, then AIDL versions 1–5 | stayed typed |
| Android 11 → 17 | TV tuner | Typed throughout. The AIDL rewrite at Android 13 merged the two HIDL enums into one and kept the shape | stayed typed |
| Android 16 | TV media quality | New HAL. 96 parameter names as an enum in the interface, 112 one version later, and a second method for vendor parameters | took typed |
| Android 8 → 13 | Audio | HIDL read everything through getParameters(vec<ParameterValue> context, vec<string> keys). AIDL replaced the known set with typed methods and kept a string-id read for vendor parameters only |
strings → typed, vendor set left beside |
| Android 8 → 10 | Power → power stats | Statistics were methods on the Power HAL: getPlatformLowPowerStats() in [email protected], then a second method, getSubsystemLowPowerStats(), in [email protected]. [email protected] replaced both with product-returned lists read by vec<uint32_t> ids. The AIDL IPower carries no statistics |
typed → beside |
| Android 11 | Gralloc |
IMapper 4.0 introduced buffer metadata with the list in a separate package, and recorded why |
designed beside |
| Android 13 → 14 | Vehicle |
VehicleProperty moved out of the interface package into android.hardware.automotive.vehicle.property
|
typed → beside |
The vehicle move states its reason in the commit, 4247384b, 2023-01-05:
Split VHAL property definitions and enums out from the VHAL interface so that we can update the property separatly. This allows us to backport new property definition to older releases more easily.
The reason given is cadence — revising the list apart from the interface, and reaching releases already shipped — and the destination is a separate AIDL package rather than another definition language. The two packages have so far frozen together: version 2 at Android 14, 3 at 15, 4 at 16.
android.hardware.wifi.common (Android 15) and android.hardware.drm.common (Android 16) are also types-only packages split out of a HAL. Their commits give sharing between HALs as the reason, so they are not evidence on cadence.
Each HAL directory names its owners, and the shape tracks them. No owner is shared between a typed-in HAL and a beside HAL.
Owners, from each OWNERS file at android-17.0.0_r1
|
HALs | Shape |
|---|---|---|
quxiangfang, shubang — the TV team |
TV tuner, TV media quality | both typed, both read by an enum array |
ADPF_OWNERS in frameworks/base
|
thermal, power | both typed |
apelosi, dvander, wjack, zhengdaniel
|
health | typed |
darrenhsu, joaodias, krossmo, vincentwang
|
power stats | beside |
the media codec authors — taklee, pawin, wonsik
|
Codec2 | beside |
frameworks/av camera owners |
camera | beside |
| the car services owners | vehicle | typed at Android 13, beside from 14 |
| core graphics owners | gralloc, graphics.common
|
beside |
So TV media quality taking the typed shape at Android 16 is the tuner's owners repeating their own design, not a second independent choice. The vehicle move runs the other way in the same sense: commit 4247384b was written by shanyu, the principal author of the vehicle AIDL HAL with 269 commits to it, so the team that had lived with the list inside its interface for a release is the team that moved it out.
Two people appear among the main authors of three or more of these HALs, smoreland in seven and devinmoore in four, both across typed and beside HALs alike. Nothing in the tree or the guidance assigns a shape centrally.
Android publishes no statement that HALs should move from one shape to the other. It publishes the rule both shapes follow. From AIDL API guidelines and Stable AIDL on source.android.com, retrieved 2026-09-21:
Enums should be closed sets. Note: only the interface owner can add enum elements. If vendors or OEMs need to extend these fields, an alternative mechanism is needed.
Whenever a client or server of the API is released (for example, in a Mainline train), you need to take a snapshot and make a new version. For system-to-vendor APIs, this should happen with the yearly platform revision.
Generally, for types-only or common packages, this is safe because code needs to already be written to handle unknown types from IPC transactions. In Android platform code
android.hardware.graphics.commonis the biggest example of this type of version upgrade.
Use strongly typed
parcelableobjects instead of serialized strings or JSON over IPC.
An enum is for a list with one owner. A system-to-vendor interface is revised once a year. A list that must move otherwise goes into a types-only package, which is upgraded apart from the interfaces that import it. Every row of the history is consistent with that.
| Path | What the interface declares | Where the list lives | Size, Android 10 → 17 | Interface versions |
|---|---|---|---|---|
| mediametrics |
oneway void submitStructuredItem(in android.media.metrics.StructuredItem p) — Property[], each { @utf8InCpp String mName; Value mValue; } over a union of int, long, double, String and a Rate pair. Android 12–16 carried submitBuffer(in byte[] buffer). |
Property names are free strings declared nowhere. Component keys — audiotrack, codec, mediadrm, videofreeze — are @utf8InCpp const String constants in the AIDL, not an enum. |
26 → 46 android.media.mediacodec.* keys |
one method, its parameter replaced once at Android 17 |
IStats vendor atoms |
oneway void reportVendorAtom(in VendorAtom vendorAtom); VendorAtom { String reverseDomainName; int atomId; VendorAtomValue[] values; }
|
.proto files outside the interface; Pixel's is pixelstats/pixelatoms.proto
|
Pixel: 3 → 67 (Android 10 → 16; the project has no Android 17 tag) |
android.frameworks.stats: 1 2
|
The HIDL interface [email protected]::IStats declared ten oneway methods through Android 16: nine named for a particular event, plus a generic carrier. At android-17.0.0_r1 the HIDL interface is deleted and only the AIDL one remains.
reportSpeakerImpedance reportBatteryHealthSnapshot reportUsbPortOverheatEvent
reportHardwareFailed reportSlowIo reportSpeechDspStat
reportPhysicalDropDetected reportBatteryCausedShutdown reportChargeCycles
reportVendorAtom
The AIDL interface declares one method:
@VintfStability
interface IStats {
oneway void reportVendorAtom(in VendorAtom vendorAtom);
}All nine of the typed methods are now entries in Pixel's vendor atom vocabulary, each carrying the annotation // moved from atoms.proto:
| HIDL method | Vendor atom | Id |
|---|---|---|
reportSpeakerImpedance |
VendorSpeakerImpedance |
105013 |
reportChargeCycles |
VendorChargeCycles |
105018 |
reportHardwareFailed |
VendorHardwareFailed |
105019 |
reportSlowIo |
VendorSlowIo |
105020 |
reportSpeechDspStat |
VendorSpeechDspStat |
105021 |
reportPhysicalDropDetected |
VendorPhysicalDropDetected |
105022 |
reportUsbPortOverheatEvent |
VendorUsbPortOverheat |
105023 |
reportBatteryHealthSnapshot |
VendorBatteryHealthSnapshot |
105026 |
reportBatteryCausedShutdown |
VendorBatteryCausedShutdown |
105027 |
Google published no statement of why the typed methods were dropped — the change landed on an internal Gerrit and the public commit log is not readable anonymously. The table is what the source records, and no motive is claimed beyond it.
- Neither shape is the exception, and neither is being retired. Six HALs type their list into the interface and seven keep it beside; a claim that Android HALs do only one of these is wrong in either direction.
- The TV tuner is the closest Android match to an enum-array selector on an AV HAL, and it is shape 1.
-
IStatsis not a device HAL. It is a framework-provided service that vendor daemons call, and it does not appear in the device compatibility matrix. Anyone looking forIStatsamong the AV HAL implementations is right not to find it. - Audio core and DRM are vendor-scoped surfaces. Their vocabularies are explicitly outside any platform contract, which makes them weaker precedent than Codec2, camera or gralloc.
- The vehicle HAL does not demonstrate independent cadence. Both its packages show four versions. It demonstrates the separation, not the benefit.
-
The core
atoms.protocount is not comparable across the whole range. From Android 14 atoms increasingly live in per-module directories, so the in-file figure understates the vocabulary from then on: 370 in-file at Android 12 with no module directories, against 120 in-file and 110 module directories at Android 17.
Every figure and quotation is read at android-17.0.0_r1, the current Android release and the newest state AOSP publishes. The main branch is not used: for hardware/interfaces it has not moved since 2025-03-26 and is 3,249 commits behind this baseline.
Commits the tables above were read at:
| Project | Commit |
|---|---|
platform/hardware/interfaces |
0162af698935100a590b7359581ac8b1b80693e5 — the android-17.0.0_r1 commit |
platform/frameworks/av |
475269ec44acec82792be6b01fb8e16357d4d2c8 |
platform/system/media |
440eb272fd3da0ca7bdae932e61e7fd9be1fd324 |
platform/frameworks/hardware/interfaces |
9de6d032a248523c22d0bd86e224d1762355c41e |
platform/frameworks/proto_logging |
a07b791ea1e2a4dae1c535c8423235fdc22aaf02 |
platform/frameworks/native |
ae266dcb706d083868578cfedce381ef44488a07 |
platform/hardware/google/pixel |
b3d2fee9bf2b42569aef7318b84b17026adfc597 — the android-16.0.0_r1 commit, its newest |
Files quoted, at those commits:
| Date | Author | Comments |
|---|---|---|
| 22nd September 2026 | G. Weatherup | Initial revision |