Skip to content

Commit 47cb9d0

Browse files
committed
Charging: Record the HONOR hardware measurement in the ledger
The Magic8 Pro contributor (issue #66) ran the dumpsys measurement, and the result is unfavourable in a way the mapping alone could not show. The cap is real: 278 mAh went into the cell after the feature was disabled, at a point where the broadcast had reported level 100 for over a minute. That confirms the synthetic 100% against the broadcast rather than the status bar, so the session-engine hazard recorded earlier is now evidenced instead of inferred. But it is only ~4%. The C636 variant is the 7100 mAh model, corroborated by the contributor's own ~7121 mAh reading, so Smart battery capacity is a top-of-charge voltage trim, not an 80%-cap equivalent, which would have plateaued near 5800 mAh. Combined with Smart charge reaching 100% overnight, neither HONOR key is a hard cap. An adapter here could offer Adaptive on and off with no percentage at all, carrying the allowsFullCharge honesty gap already recorded for Xiaomi. The open question is therefore no longer whether the mapping works but whether that adapter is worth building. Noted that the ~4% figure is a ratio, so it survives the charge-counter unit question. policyLatchesAtPlug behaviour observed: disabling the feature with the cable connected moved nothing, and the charge only went in after a replug. Same family as GrapheneOS, so an adapter would reuse the existing pending-until-replug handling and could not support the reconnect gesture. Blocker 2's identity mechanism is resolved. MagicOS exposes app-readable system features and core com.hihonor.* system packages, the same two mechanisms that already carry LineageOS and GrapheneOS, so no property read is needed. Version scoping is still unsolved: com.hihonor.magic.api.23 does not line up with ro.build.magic_api_level=42, so the features answer "is this MagicOS" and not "is this MagicOS 10", and a features-only gate would be the first unscoped one in the project. Records the three app defects the device exposed, one fixed here, one deferred by decision (the hasSupportLead gate hides the metadata report on exactly the unrecognized ROMs whose codename it would carry), and one awaiting a single contributor reading.
1 parent ac69fd6 commit 47cb9d0

1 file changed

Lines changed: 84 additions & 3 deletions

File tree

  • .claude/skills/device-qualification

.claude/skills/device-qualification/SKILL.md

Lines changed: 84 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -367,6 +367,24 @@ only after adding a row here. Detailed run narratives live in each adapter's lan
367367
are compile-time constants, the AIDL has no property op
368368
(`IChargingControlService.aidl`), and `SystemPropertyReader` structurally cannot distinguish denial from
369369
absence — so probing a candidate MagicOS property needs a code change, not a contributor run.
370+
- **Blocker 2, IDENTITY MECHANISM RESOLVED (support mail, 2026-08-17); version scoping still open.** The
371+
contributor supplied both lists from `HNBKQ`. App-readable signals now known to exist on MagicOS 10:
372+
- **System features** (`hasSystemFeature`, no permission, no `<queries>` entry — the LineageOS pattern):
373+
`com.hihonor.software.features.honor`, `com.hihonor.system.feature`,
374+
`com.hihonor.software.features.full`, `com.hihonor.software.features.handset`,
375+
`com.hihonor.software.features.oversea`, `com.hihonor.magic.api.23`.
376+
- **Core system packages** (PackageManager + `FLAG_SYSTEM` — the GrapheneOS pattern):
377+
`com.hihonor.systemserver`, `com.hihonor.systemmanager`, `com.hihonor.powergenie`,
378+
`com.hihonor.controlcenter`, `com.hihonor.android.launcher`.
379+
- Properties exist too (`ro.build.version.magic=MagicOS_10.0.0`, `ro.build.magic_api_level=42`,
380+
`ro.magic.cversion=C636`) but stay the **wrong** route for the SELinux reason above; they are recorded
381+
only as corroboration. `ro.product.device=HNBKQ` confirms the fingerprint-derived codename.
382+
**What is still missing is ROM-generation scoping.** `com.hihonor.magic.api.23` does not line up with
383+
`ro.build.magic_api_level=42`, so that feature reads as a fixed namespace marker rather than a version
384+
discriminator — i.e. the features answer "is this MagicOS", not "is this MagicOS 10". Every existing OEM
385+
gate is version-scoped (One UI range, `ro.mi.os.version.code`, `oplusrom == 15`); a features-only HONOR gate
386+
would be the first that is not, which is exactly the weakness called out above for `Build.MANUFACTURER`.
387+
Resolve that before any gate is written, not after.
370388
- **Level-reporting hazard to test at qualification.** The reporter states Smart battery capacity "still
371389
displays 100% when fully charged" while capping. A ROM reporting a synthetic 100% at a real ~80% would
372390
trip `full = status == BATTERY_STATUS_FULL || percent >= 100` in `ChargeSessionService`, ending a session
@@ -393,6 +411,34 @@ only after adding a row here. Detailed run narratives live in each adapter's lan
393411
`dumpsys battery`, then switch the feature OFF with the cable in and re-record. Voltage and charge counter
394412
climbing afterwards proves the cap is real and the 100% cosmetic; unchanged means the cell was already full
395413
and the mode caps nothing. Same evidence shape that settled `tanzanite`.
414+
**RESULT (2026-08-17), and it reframes the feature.** Contributor-run, `HNBKQ`:
415+
416+
| State | Charge counter | status | level | voltage |
417+
| --- | --- | --- | --- | --- |
418+
| Smart battery capacity ON, plugged, HONOR showing 100% (stable ≥1 min) | 6978 | 2 | 100 | 4551 |
419+
| Feature OFF, cable never removed | 6978 (unchanged) ||||
420+
| Feature OFF, after unplug→replug | 7256 | 5 | 100 | 4421 → 4472 |
421+
422+
- **The synthetic 100% is CONFIRMED in the broadcast, not just the status bar.** `level: 100` with 278 mAh
423+
of real headroom, so the sharpenings above are now evidenced rather than inferred. The dumpsys `status: 2`
424+
alongside a flat counter also means the ROM reports "charging" while holding.
425+
- **But the cap is only ~4%, so Smart battery capacity is NOT an 80%-cap equivalent.** The C636/Singapore
426+
variant is the 7100 mAh model (China 7200, Europe 6270; the contributor's own AIDA64 reading of ~7121 mAh
427+
corroborates), so 278 mAh ≈ 3.8%. An 80% cap would have plateaued near 5800 mAh. This is a
428+
top-of-charge voltage trim, a different class of feature from every currently supported adapter.
429+
Consequence: **neither HONOR key is a hard cap** — Smart charge is adaptive (reaches 100% overnight),
430+
Smart battery capacity trims ~4% — so an adapter here could offer Adaptive on/off and no percentage at
431+
all, with the `allowsFullCharge` honesty gap applying. Weigh that against the build cost before
432+
committing to a MagicOS adapter; the mapping being correct is no longer the deciding question.
433+
- **`policyLatchesAtPlug` behaviour OBSERVED.** Disabling the feature with the cable in moved nothing; the
434+
278 mAh only went in after unplug→replug. Same latch-at-plug-session-start family as GrapheneOS, so an
435+
adapter would need `policyLatchesAtPlug = true`, the pending-until-replug state, and the replug grace
436+
window rather than anything new. The reconnect gesture would be unsupported for the same timing reason.
437+
- Caveats: single run, one sample per state, and the voltage column is not interpretable across rows
438+
(4551 was measured under charge, 4421 at `status: 5` resting). The charge counter is the load-bearing
439+
number. Note the ~4% figure is a **ratio** (6978/7256), so it survives the charge-counter unit question
440+
raised by the telemetry defect below — a uniform 1000× scaling cancels. Only the absolute
441+
"278 mAh" framing depends on the unit, and the nominal-capacity cross-check independently supports mAh.
396442
- **Third key, out of scope: `secure/charge_separation_all_scenarios_switch`** (bypass charging, `1`/`0`,
397443
reported 2026-08-16). Contributor observation: bypass engages while the screen is on and normal charging
398444
resumes with the screen off. Recorded as context only — Amply has **no bypass concept at all** (the sole
@@ -405,7 +451,42 @@ only after adding a row here. Detailed run narratives live in each adapter's lan
405451
"Just send device info" action on the unsupported-device card (`DeviceSupportReporter` emits `device=`
406452
from `Build.DEVICE`, plus `brand`/`product` and the tri-state key probes; no Shizuku needed) rather than
407453
another wizard pass, which would omit the codename again.
408-
- **Status after the 2026-08-16 follow-up: still NOT qualified, and the gate is unchanged.** One of Blocker
409-
1's two halves is closed (keys drive the OEM UI both ways, mirror class excluded); the hardware half and
410-
all of Blocker 2 are open. Nothing here justifies an adapter, a lab adapter, or a manufacturer read.
454+
- **Three app defects this device exposed (2026-08-17), two of them not HONOR-specific.**
455+
- **`FIXED`: "Open battery settings" landed on Battery Saver on every unmapped device.**
456+
`ChargingRepository.nativeSettingsIntent()` returned null for `adapter == null` and its only caller
457+
substituted `ACTION_BATTERY_SAVER_SETTINGS` outright, so `ACTION_POWER_USAGE_SUMMARY` was never tried —
458+
despite every lab adapter preferring it, and despite the manifest already declaring its `<queries>`
459+
visibility. Same user-visible symptom as the LineageOS case above, reached by a different path (that one
460+
fell through to the Pixel component intent; this one had no adapter object to ask). Affected HONOR,
461+
Motorola, Nothing, Sony, Fairphone, Vivo, Tecno — anything without an adapter. Fixed by making the
462+
repository fall back to `OemChargingShortcuts.genericBatterySettings`, with the chain extracted so the
463+
lab adapters and the null path share one implementation. **Not confirmed to change what this contributor
464+
sees**: whether `POWER_USAGE_SUMMARY` resolves on MagicOS 10 is still unverified.
465+
- **OPEN (deferred, deliberate): "Just send device info" cannot appear on an unrecognized ROM.**
466+
`UnsupportedDeviceCard.kt` gates it on `hasSupportLead` (`ChargingRepository.kt`), a ten-way disjunction
467+
of known-ROM markers, every one of which is structurally false for HONOR. Shipped in `v0.3.2-beta0`
468+
(`bc55ceb`, PR #44) with a pinning test, so this contributor's build could never have shown it. The gate
469+
is defensible (it exists to avoid dead-end reports) but perverse here: the less Amply recognizes a
470+
device, the less it lets the user report it — and the report being withheld is the only one carrying
471+
`Build.DEVICE`, which is exactly what an allowlist entry needs. This contributor hand-dumped properties
472+
because of it. Held rather than changed: reversing a deliberate decision on one data point is thin, and
473+
the Shizuku wizard path was still open to them. Revisit if another unknown-ROM contributor hits it.
474+
- **OPEN (needs one device reading): charge power renders `0.0 W` / `4 mA` while charging.** Both figures
475+
come from one field, `BATTERY_PROPERTY_CURRENT_NOW`. A ROM reporting mA where Android documents µA turns
476+
a real 4 A into the integer `4000`, which formats as "4 mA" and computes to
477+
`4551 mV × 4000 µA / 1e6 = 18 mW`, printing as "0.0 W" — reproduced exactly in
478+
`StatsPowerCalculatorTest`. `Charge counter: 6978` points the same way (documented µAh; 6978 µAh would be
479+
6.98 mAh). **But an end-of-charge trickle at level 100 produces the identical value**, so the number
480+
alone cannot decide, and a low-side clamp would break correct readings on healthy devices — the
481+
`MAX_PLAUSIBLE_MILLIWATTS` guard only ever caught the *over*-reporting direction, and its test comment
482+
asserted the wrong direction outright (both corrected). Deciding reading requested: Amply's own
483+
"Charge counter" row should render **~7 mAh** if the ROM scales that property, independent of charging
484+
state. No per-device telemetry seam exists (`ChargingAdapter` carries no unit capability and
485+
`BatteryReader` never sees a `DeviceInfo`), so a fix is new work — and it is adapter-independent, since
486+
this device has no adapter to hang it on.
487+
- **Status after the 2026-08-17 follow-up: still NOT qualified.** Blocker 1's hardware half is now ANSWERED
488+
but the answer is unfavourable — the cap is real yet only ~4%, and neither key is a hard limit, so the open
489+
question is no longer "does it work" but "is an Adaptive-only MagicOS adapter worth building". Blocker 2's
490+
identity mechanism is resolved; its version scoping is not. Nothing here justifies an adapter, a lab
491+
adapter, or a manufacturer read yet.
411492
- Tracking: GitHub issue #66.

0 commit comments

Comments
 (0)