Skip to content

feat(wearable): integrate enhanced Wear OS support - #3877

Open
CMKIXVI wants to merge 11 commits into
microg:masterfrom
CMKIXVI:bounty/wearos-2843-submit-v8
Open

CMKIXVI wants to merge 11 commits into
microg:masterfrom
CMKIXVI:bounty/wearos-2843-submit-v8

Conversation

@CMKIXVI

@CMKIXVI CMKIXVI commented Oct 11, 2026

Copy link
Copy Markdown

Addresses #2843.

Builds on the existing Wear OS implementation and adds fail-closed handling for SystemProperties linkage failures, with regression coverage.

joannadal4 and others added 11 commits October 3, 2026 11:53
Auth requests carry account credentials, and their responses carry
tokens and, for web login, continuation URLs with session material.
GCM registration requests carry the device security token and their
responses an instance token. HttpFormClient logged all of these in full
at debug level. Requests can now opt out of content logging; AuthRequest
and RegisterRequest always do.
Add the Pixel Watch companion with its exact signing certificate to the
known Google packages, so it can list the accounts it needs to copy to
a watch. Only authentication-capable packages may clear passwords.

A package-filtered account query could omit accounts whose visibility
had never been decided, and the previous check could not tell a stored
user choice from the platform default. Grant discovery before querying,
and only where no explicit visibility choice exists.
Newer Wearable SDK clients send request/response messages (RPC) and
expect typed callbacks that the AIDL interfaces did not declare, so
their calls could not be answered. Add the RPC request/response types,
MessageOptions, the account-consent parcelables and the callbacks for
channel, capability and cloud-sync responses.
…nd media bridge

Previously the service could only listen on TCP port 5601, so a real
watch could never connect, and channels, capabilities and several other
calls were stubs that never answered.

Transport
- Connect over a paired, secure Bluetooth RFCOMM link. Saved
  connections are restored on start and retried with backoff (3-30 s);
  disabling or deleting one closes it.
- Keep the TCP bridge for development only: loopback, debuggable build
  on an emulator, one emulator at a time.
- Import the connection classes from microg/Wearable (attribution kept)
  so they can be fixed here: a peer only counts as connected after
  negotiating a node id and protocol version, and message assembly is
  bounded (16 MiB, eight queues, 64 KiB pieces).

Data Layer
- Implement channels with flow control and an open timeout.
- Implement RPC in both directions; keep RPC sequence numbers separate
  from channel traffic so replies no longer wait for missing messages.
- Implement local/connected capabilities and notify manifest and
  runtime listeners, rechecking the listener's package and certificate.
- Fix literal/prefix filters, wildcard queries, asset grouping and
  transactional deletion of data items.
- Answer unsupported calls (cloud sync, Wi-Fi credentials, account
  consent association) with a terminal status instead of no reply.

Media
- Add WearableMediaBridge, a notification listener that publishes the
  active MediaSession to the watch and accepts bounded commands only
  from the verified companion. Revoking access removes the state.

Consent
- Store the Wear OS terms decision privately so the terms screen and
  the service share it; only the verified companion may change it.
Register WearableMediaBridge as a notification listener (Android 5.0+),
so the user can grant it access from the system settings and the watch
can show and control what is playing on the phone.

On Android 12+, talking to a paired watch needs BLUETOOTH_CONNECT; add
it to the permissions requested and checked by the self-check screen.
TermsOfServiceActivity answered "cancelled" as soon as the companion
opened it, so the terms could never be accepted and watch setup could
not go on. Show the terms with links, record an explicit acceptance in
the private consent store shared with the Wearable service, and keep
optional consents disabled.

Only the verified companion may open the screen; its identity is
checked again before the decision is saved, restored activity state
never turns into a decision, and obscured touches are ignored.

Also enable instrumented tests for play-services-core.
Copying an account to a watch requires the phone to sign bootstrap
assertions with keys that CryptAuth knows for that account. microG only
reported the screen-lock state and had no enrollment of its own.

- Enroll per-account keys and keep them, with their OTP counters, in
  private storage excluded from backups. Keys become active only after
  the server confirms them; revocations and counters are kept.
- Complete a synchronization without sending EnrollKeys when the server
  needs no new keys, and never rotate keys during a transfer.
- Build assertions from the enrolled state and the public key already
  announced to the peer, rechecking authorization when the counter is
  reserved.
- Serialize CryptAuth state changes, keep the existing screen-lock
  report, and log failures by exception class only, since exceptions
  from these services can contain secrets.
When the Pixel Watch companion asked the phone to copy an account to a
watch, microG answered with a dummy service, so watches were left
without an account. Implement the source side of the direct-transfer
service.

- Accept requests only from the official companion, verified by
  package, signing certificate and Binder UID.
- Show a microG consent screen naming the target watch and the
  selected account, and require the device credential; refuse devices
  without a secure screen lock and managed or supervised requests. An
  explicit empty account list from the companion allows no account.
- Encrypt the session with UKEY2/D2D before exchanging account data,
  then run the bootstrap protocol with CryptAuth-signed assertions.
- When Google asks for interactive verification, show its page in an
  isolated WebView profile in the :persistent process. Only
  accounts.google.com may be loaded, only the resulting checkpoint
  cookie is used, and cookies are removed and flushed and the profile
  deleted afterwards. The password is never seen by microG.
- Report success only after the watch confirms the selected account
  and the final acknowledgement has been written. Cancellation,
  timeouts and malformed messages end the transfer with a fixed reason;
  logs never contain account names, tokens or payloads.

UKEY2 is checked against vectors generated by the google/ukey2 Java
reference implementation.
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.

2 participants