Skip to content

putbytes: check the install response cookie again - #398

Open
zunda-pixel wants to merge 3 commits into
coredevices:masterfrom
zunda-pixel:putbytes-install-cookie
Open

putbytes: check the install response cookie again#398
zunda-pixel wants to merge 3 commits into
coredevices:masterfrom
zunda-pixel:putbytes-install-cookie

Conversation

@zunda-pixel

@zunda-pixel zunda-pixel commented Sep 3, 2026

Copy link
Copy Markdown

Client side of coredevices/PebbleOS#1987. That PR fixes the firmware; this one restores the check that had to be given up because of it.

The TODO, answered

suspend fun sendInstall(cookie: UInt) {
    val installResponse = putBytesService.sendInstall(cookie)
    // TODO this fired?
//    check(installResponse.cookie.get() == cookie) { "Received response for wrong cookie" }
}

It fired because the watch answers an install with cookie 0, not because the cookie was ever wrong.

In src/fw/services/put_bytes/put_bytes.c, prv_do_install answers through prv_cleanup_and_send_response, which reads s_pb_state.token — and the COMMIT that always precedes an install has already run prv_cleanup, which resets the transfer state. The firmware does validate the phone's token (prv_do_install looks it up in s_ready_to_install[] and NACKs a mismatch); it just never echoed it. sendPut and sendCommit are unaffected, which is why only this one check had to go.

What this changes

Zero is tolerated rather than assumed, so the check comes back for firmware that answers with the install's own token, while a cookie belonging to some other transfer is still caught. Nothing changes against firmware in the field.

Tolerating zero cannot mask a real mismatch, because zero is never a valid token:

const uint32_t r = rand();
s_pb_state.token = MAX(1, r);   // put_bytes.c — a real token is never zero

and prv_do_install rejects token == 0 outright. Gating on firmware version instead would mean threading a version dependency into PutBytesSession, which currently takes only putBytesService, for no gain over this.

Tests

PutBytesSessionTest covers the three answers an install can get: its own cookie, zero, and another transfer's. The middle one is what the firmware sends today; the last is what the check is still there to catch.

./gradlew :libpebble3:jvmTest --tests '*PutBytesSessionTest'
  anInstallAnsweredWithItsOwnCookieIsAccepted   PASS
  anInstallAnsweredWithZeroIsAccepted           PASS
  anInstallAnsweredForAnotherTransferIsNot      PASS

Full suite on this branch: 209 tests, no failures. Reverting the || responseCookie == 0u half of the check fails anInstallAnsweredWithZeroIsAccepted and nothing else, so the test pins what this PR changes.

Correcting my own earlier note: an earlier version of this description said I could not compile or run Kotlin here. That was wrong — I had not tried properly. The tree does have a Gradle wrapper; :libpebble3:compileKotlinJvm and :libpebble3:jvmTest both work once local.properties names an Android SDK and a JDK 17 is on the toolchain path.

The firmware side has two regression tests in coredevices/PebbleOS#1987, so the behaviour is covered from the other end.

Landing order

This wants to land with or after the firmware PR. On its own the || responseCookie == 0u reads oddly without the other half of the story.

AI use

Written with Claude Code (Claude Opus 5), disclosed per CONTRIBUTING. The diff is nine lines; I have read it and the firmware path it describes, and can explain either.

The check was commented out with "TODO this fired?" — it fired because
the watch answers an install with cookie 0, not because the cookie was
wrong. In prv_do_install the firmware reads s_pb_state.token for the
response, and the commit that always precedes an install has already
reset that state, so zero is what a phone gets back. Every other step
here keeps its cookie check; only the install had to give one up.

Zero is tolerated rather than assumed, so the check returns for firmware
that answers with the install's own token, while a cookie belonging to
some other transfer is still caught.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@CLAassistant

CLAassistant commented Sep 3, 2026

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

Its own cookie, zero, and somebody else's. The middle one is what the
firmware sends today and the reason the check was commented out; the last is
what the check is still there to catch.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@gmarull
gmarull requested a review from sjp4 September 5, 2026 11:05
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.

3 participants