Skip to content

feat: deliver signed SABR compatibility profiles#78

Open
Priveetee wants to merge 3 commits into
InfinityLoop1308:devfrom
Priveetee:feat/sabr-compatibility-profile
Open

feat: deliver signed SABR compatibility profiles#78
Priveetee wants to merge 3 commits into
InfinityLoop1308:devfrom
Priveetee:feat/sabr-compatibility-profile

Conversation

@Priveetee

@Priveetee Priveetee commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

Summary

This PR adds the Android delivery side of SABR compatibility profiles.

PipePipeExtractor defines and evaluates the signed profile. PipePipe Client decides when Android downloads one, how it survives process restarts, which revision a new playback session receives and how a bad revision is disabled. Existing SABR sessions and the bundled policy remain usable when the network, endpoint, cache or profile is unavailable.

The remote path is build-time opt-in. With no endpoint or public keys configured, the application schedules no update work and every session follows the bundled Extractor behavior.

Android lifecycle

App startup
  -> restore stable or beta profile state
  -> expose one immutable snapshot to each new SABR session
  -> schedule an immediate update
  -> schedule a network-constrained update every six hours

HTTPS response
  -> bounded download
  -> Extractor verification
  -> atomic active/previous cache update
  -> independent revision-floor update
  -> activate for future sessions

App initializes SabrPolicyRuntime before playback and then starts SabrPolicyUpdateWorker. SabrSessionStore asks the runtime for a new SabrSessionPolicyHost whenever it creates a SABR session.

A session snapshots the current immutable profile at creation time. Installing a newer revision does not mutate playback already in progress.

Build configuration

The Android build accepts three values:

  • SABR_COMPATIBILITY_PROFILE_PUBLIC_KEYS: up to eight key-id=base64-public-key entries for Ed25519 key rotation
  • SABR_COMPATIBILITY_PROFILE_STABLE_URL: HTTPS endpoint selected by stable versions
  • SABR_COMPATIBILITY_PROFILE_BETA_URL: HTTPS endpoint selected by versions containing -beta

Stable and beta use different cache files and different monotonic revision floors. This prevents a beta profile from becoming trusted state for a stable build.

No configured URL or no configured trust roots means remote delivery is completely inactive. The worker is not scheduled, the endpoint is not contacted and SabrPolicyRuntime returns the bundled policy.

Update behavior

SabrPolicyUpdateWorker uses the application's existing HTTP client with redirects disabled and accepts only an HTTPS endpoint. The response body is bounded to the Extractor document limit before installation.

Response handling is explicit:

  • 200: verify and install the document
  • 204 or 304: no update, successful check
  • 408, 425, 429 or 5xx: ask WorkManager to retry
  • other status: record the rejection and wait for the next scheduled check
  • I/O failure: retry
  • invalid document or configuration: reject without a retry loop

The endpoint distributes only a public signed document. It does not receive playback requests, cookies, PO tokens, media URLs or media bytes.

Persistence transaction

SabrProfileCache uses Android AtomicFile storage for two independent pieces of state:

  1. the active document, previous document and circuit-breaker fallback marker;
  2. the highest accepted revision.

SabrProfileRegistry.install() verifies the downloaded document first, persists the new active/previous state, persists the new revision floor and only then exposes the revision in memory. If writing the floor fails, it restores the previous cache state instead of activating a partially committed update.

Keeping the floor separate is deliberate. Corrupting or deleting the active-document cache must not allow an older signed revision to be installed later. A revision rejected by the circuit breaker also remains the floor, so recovery requires a higher signed revision rather than a replay of the document that just failed.

SabrProfileRestorer distinguishes normal active restoration, previous-generation restoration and the circuit-breaker fallback case. Invalid, expired, corrupted or inconsistent cached state is discarded and startup continues on the bundled policy.

Session selection and recovery

SabrPolicyRuntime.createSessionHost() has three outcomes:

  • no valid profile: create a host with BuiltinSabrSessionPolicy;
  • valid profile for the selected WEB/MWEB client: wrap it in FallbackSabrSessionPolicy;
  • valid partial profile that omits the selected client: use the bundled policy for that session without disabling the signed revision.

When a profiled session trips its circuit breaker, that session immediately uses the bundled behavior. The registry disables the same revision for future sessions and restores the previous valid document when available.

The disable callback checks both the registry instance and the exact captured profile. A failure from an old session therefore cannot disable a newer revision installed while that session was still running.

The active document, previous document and revision floor are private application state. Diagnostics are limited to revision numbers and failure classes; request bodies, response payloads, cookies, PO tokens and media bytes are not persisted or logged.

Changes

  • initialize the compatibility-profile runtime during application startup
  • add stable/beta endpoint and public-key build configuration
  • fetch bounded profile documents over HTTPS with WorkManager
  • restore active and previous revisions across process restarts
  • persist a monotonic revision floor independently from cached documents
  • give each new SABR session an immutable profile snapshot
  • disable only the exact failing revision and recover to previous or builtin behavior
  • keep debug-only builtin/profile selection for instrumentation and comparison
  • add instrumentation coverage for install, restart, corruption, rollback and runtime fallback
  • remove the disabled QuickJS runtime, script asset and cloud-policy documentation
  • document the Android delivery and recovery contract

Validation

Build validation with all profile endpoint and public-key values unset:

  • ./gradlew --no-daemon :app:assembleDebug :app:assembleDebugAndroidTest :app:lintDebug

Android instrumentation covers:

  • valid and invalid signatures, key rotation and monotonic revision rejection
  • active/previous restoration and independent stable/beta state
  • atomic-install failures, cache corruption and process restart
  • persisted circuit-breaker fallback and rejection of the failed revision
  • WEB-only documents leaving MWEB on builtin behavior
  • shifted request fields, UMP media part types and media-header protobuf fields
  • the existing SABR download pump and following-request path
  • five existing retry/backoff scenarios

Real Pixel 8 playback validation:

  • signed MWEB playback rendered hardware VP9 video and Opus audio with zero dropped frames
  • signed WEB playback rendered the same path with zero dropped frames
  • seeking and background/reopen kept playback active
  • AV1 selection used the hardware vendor decoder
  • a broken required mapping disabled the signed revision and continued with builtin behavior
  • a signed MWEB playback soak ran for 331 seconds and reached 3,005 seconds of media time without a terminal playback failure
  • retained SABR cache stayed at about 6.8 MiB; the transient peak remained under the measured 38.9 MiB bound

Deployment status

This PR contains no production endpoint, signing private key or enabled trust root. It is safe by default: without build-time configuration, its runtime behavior is the existing bundled SABR policy.

The profile publisher and key-management process need to be reviewed separately before remote delivery can be enabled in a release.

Related PR

@Priveetee
Priveetee force-pushed the feat/sabr-compatibility-profile branch from 3d27217 to 8db93cd Compare July 23, 2026 07:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant