feat(release): bake real interface version + contract hash into snapshots at freeze - #634
Conversation
…apshots (#633) Module-local snapshots are compile-only (their CMakeLists glob src/*.cpp and never regenerate), so getInterfaceVersion()/getInterfaceHash() can only be set at freeze time. create_snapshot() now, before generating: - computes a monotonic ordinal = index of the version among the component's released versions (0.1.0.0->1, 0.2.0.0->2, ...) - computes the contract hash (sha1 of sorted per-file .aidl sha1sums + version_for_hashgen label), matching the toolchain's integrity check - stamps current/ with 'version: <ordinal>' + .hash, generates (the version-aware generator emits them), copies into the snapshot, restores current/, and records the snapshot's .hash Verified end-to-end (audiodecoder, ordinal 2): the snapshot emits VERSION = 2 and HASH = <real sha>, imports still resolve (the generator decouples emit-version from resolution-version), and the library builds. Graceful: with the current generator the .hash already flows (HASH correct, VERSION stays 1); the ordinal takes effect once linux_binder_idl #33 is merged and binder_sdk.version is bumped. Refs #633, #32
There was a problem hiding this comment.
Pull request overview
Updates the release freeze workflow so module snapshots embed a real, monotonic interface version (ordinal) and a deterministic contract hash into the generated Binder stubs at snapshot creation time. This addresses clients always seeing getInterfaceVersion() == 1 / getInterfaceHash() == "notfrozen" for frozen snapshots.
Changes:
- Added helpers to compute a snapshot ordinal, compute a contract hash, and stamp
current/interface.yamlwithversion: <ordinal>. - Updated
create_snapshot()to temporarily stampcurrent/withversion+.hash, regenerate bindings, copy into<version>/, then restorecurrent/. - Writes the computed contract hash into the frozen snapshot as
<snapshot_dir>/.hash.
…n ordinal Per review: getInterfaceVersion() should reflect the actual version (0.2.0.0 -> 0200 -> 200), not a sequential 1/2/3 ordinal. Replace _snapshot_ordinal with _snapshot_version_int = base-10 of the version with dots removed. Verified: audiodecoder 0.2.0.0 emits VERSION = 200 (+ real hash), builds clean.
…ace-version-freeze-wiring
…633) The dot-strip encoding (0.2.0.0 -> 200) breaks once any field reaches 10 (0.10.0.0 -> 1000 == 1.0.0.0). Replace with a fixed-width positional scheme: each X.Y.Z.W field is zero-padded to two digits and concatenated, so the int32 is monotonic AND losslessly decodable (0.2.0.0 -> 20000, 1.0.0.0 -> 1000000, 0.10.0.0 -> 100000 distinct from 1.0.0.0). Fields must be 0-99; a wider field returns empty and the caller now warns + leaves the snapshot unfrozen rather than emit a wrong number. Documents that getInterfaceVersion() ordering is an additive-compat test only WITHIN a generation — a correct consumer check is generation(server)==generation(client) && server>=client, not bare >=, because the generation field marks breaking changes (see #633).
- _contract_hash: use sha256 (64 hex) to match the committed <version>/.hash format across the repo (was sha1, wrong length). - _snapshot_version_int: require exactly four numeric dot-separated fields (X.Y.Z.W) before encoding; reject malformed inputs (0.2.0, 0.2.0.0., 0.2..0) that word-splitting would silently accept and that could collide. - Correct 'ordinal' wording to 'fixed-width positional version int' in the freeze-stamp comments (the scheme encodes X.Y.Z.W, not a sequence ordinal).
|
Copilot review: the three flagged items (SHA-1→SHA-256 contract hash, strict 4-field version validation, and the positional version-int naming) were already addressed in follow-up commits — resolving the now-outdated threads. |
Re-scope (decided 2026-07-04)The ABI signals belong in the generator, not here — see linux_binder_idl#32 (now on the 2.5.0 milestone), which owns:
That makes two changes here:
What stays here: So this PR should shrink to version-stamping only, with the hash + version-emission deferred to linux_binder_idl#32. Once #32 lands (2.5.0) and the pin bump (#683 → binder 2.4.0, and later 2.5.0) is in, snapshots get correct, ABI-only cc: this came out of the review question on whether baking the hash in |
|
Tracking note: the versioning design is consolidated in #633 (now trustworthy frozen interface versioning, with #658 folded in). Per that + linux_binder_idl#32, this PR re-scopes to version-setting only — the version-ordinal and contract-hash emission move to the generator (linux_binder_idl#32/#33). |
…ace-version-freeze-wiring
Refs #633 — consumer-side half of linux_binder_idl #32 / PR #33.
Problem
getInterfaceVersion()/getInterfaceHash()return1/notfrozenfor every snapshot, so a client can't tell which interface version a service exposes. Snapshots are compile-only (their CMakeLists globsrc/*.cpp), so this can only be fixed at freeze time.Change (
create_snapshot)Before generating, it now:
0.2.0.0 → 0200 → 200,0.3.0.0 → 300,0.1.0.1 → 101;sha1of sorted per-file.aidlsha1sums + theversion_for_hashgenlabel), matching the toolchain's integrity check;current/withversion: <int>+.hash, generates (the version-aware generator emits them), copies into the snapshot, restorescurrent/, and records the snapshot's.hash.Proof (tested end-to-end, audiodecoder 0.2.0.0)
Snapshot emitted
static const int32_t VERSION = 200;andHASH = "bd961e2c…", imports still resolved (generator decouples emit-version from resolution-version), library built. Encoding spot-check:0.1.0.0→100, 0.2.0.0→200, 0.3.0.0→300, 0.1.0.1→101.Notes
0.2.0.0reads back as 200 (zero-pad to 4 digits to display0200). Assumes single-digit components (true for all current versions); a wider fixed-field scheme would be needed if a component reaches 10..hashalready flows → HASH correct; the VERSION digit-encoding activates once linux_binder_idl #33 is merged andbinder_sdk.versionis bumped..hash) by re-freezing.