Skip to content

feat: add Android arm64 Bionic support - #62

Merged
kolkov merged 4 commits into
go-webgpu:mainfrom
besmpl:besmpl/android-arm64-bionic
Jul 21, 2026
Merged

feat: add Android arm64 Bionic support#62
kolkov merged 4 commits into
go-webgpu:mainfrom
besmpl:besmpl/android-arm64-bionic

Conversation

@besmpl

@besmpl besmpl commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

Summary

Android arm64/API 29+ is ready for code review as a guarded preview candidate rebased onto current main after #63 (2bd8752a68324d4cc47343b8f3a38d154147be85). The candidate keeps the public module path and separates the review surface into dependency-ordered commits:

  1. b7a3a76f0d339bc193537bd039178f85a81ff8bf — Bionic platform loader and __errno/errno routing for cgo=0 and cgo=1.
  2. 0cb3ecb9ba84705b6d51f8b2e3d1bd5e684d25af — Android arm64 fakecgo startup, four-argument _cgo_init, API/TLS guard, Bionic layouts/imports, and explicit callback rejection.
  3. 53d06d7c96e7624eb6a69bd764e8c5cefca8a4ff — generated-source, NDK ABI, cross-build/ELF probes, CI matrix, and preview documentation.
  4. a8a33c781c0f0ab4de96b2f81834f9913e2d2a11refactor: rename purego_ → goffi_ in fakecgo + copyright update #63 alignment plus the runtime.iscgo, RTLD API, and TLS-diagnostic review follow-up.

The exact branch head is a8a33c781c0f0ab4de96b2f81834f9913e2d2a11. The previously published one-commit head is preserved at besmpl/archive/android-arm64-bionic-3d665de, 3d665de6d43af35dd6dae005ef09231c15b0d456.

Android loader mappings remain process-lifetime mappings (RTLD_NODELETE); FreeLibrary is retained for API symmetry. Android callbacks fail with a stable panic until foreign-thread startup has physical-device evidence.

Validation

The Android check passed on both audited toolchains with NDK r29 (29.0.14206865):

ANDROID_NDK_HOME=/path/to/android-ndk-r29 GOTOOLCHAIN=go1.25.12+auto ./scripts/check-android-arm64.sh
ANDROID_NDK_HOME=/path/to/android-ndk-r29 GOTOOLCHAIN=go1.26.5+auto ./scripts/check-android-arm64.sh

Each run covers CGO_ENABLED=0 and CGO_ENABLED=1, generated fakecgo freshness, Bionic LP64 header/layout assertions, AArch64 ELF dependencies, callback/glibc symbol rejection, startup/TLS disassembly, and same-call loader-error capture. Focused host go test ./ffi ./types passes in both cgo modes; root module verification, formatting, shell syntax, and diff checks are clean.

The same matrix was rerun locally against this exact head on 2026-07-21 and passed for Go 1.25.12 and Go 1.26.5. The review follow-up also asserts Android's implicit Linux-tag selection of callbacks.go, iscgo.go, and setenv.go, and verifies that no purego_ dynamic imports remain. The new upstream Actions run currently needs a maintainer to approve workflows from the fork: https://github.com/go-webgpu/goffi/actions/runs/29806270436.

Review and evidence boundary

This PR is ready for implementation review now. It does not claim released Android support: cross-build, ABI, and ELF evidence cannot prove process startup or foreign-call behavior on a physical device. API 29 and API 30+ arm64 device runs remain the outstanding acceptance evidence before Android should be advertised as supported. Android callback support remains explicitly unavailable rather than being inferred from desktop behavior.

A downstream WGPU consumer exercises the non-callback FFI path. Its host keeps Android Activity/JNI policy outside goffi, uses ordinary cgo for incoming Activity callbacks, and uses goffi only for outgoing Vulkan calls. This lets the runtime work be reviewed without expanding goffi into an Android callback framework.

Downstream integration

The corresponding pure-Go WGPU Android candidate is gogpu/wgpu#268 at exact head 041e19e65620a0a554718a712ead544794a863b5. Its temporary CI still pins the successful pre-rebase goffi head 8ccaae72d877a7af0af4b628bf86e92536e27d88; it will refresh to this PR's current head or the canonical release before its next integration claim. It uses no fork module path, replace, or committed go.work.

Rust-v29 typed surface parity is separate in gogpu/wgpu#273 at exact head d61c2152ed95a80985ff53b30df7f65fd0431367. This PR deliberately remains outbound Bionic FFI only. Activity, JNI, nativeexport, and foreign-thread entry are host/runtime work above WGPU; the experimental zero-cgo native-entry prototype is not included here and is not a merge prerequisite.

API 29 is the downstream native/install floor; API 36 compile/target is downstream host policy. Merge and release goffi#62 first, then #268 can drop its temporary pin and consume the canonical release.

@besmpl

besmpl commented Jul 15, 2026

Copy link
Copy Markdown
Contributor Author

Consumer integration: gogpu/wgpu#268 at exact head 7245d59850733b30ea218bb293e5cbde95660c6c pins this PR exact head 8ccaae72d877a7af0af4b628bf86e92536e27d88 in temporary integration CI.

The WGPU module commits no replace, go.work, personal fork path, or forked module version. Both PRs are ready for implementation review. Physical-device evidence remains an explicit support/acceptance boundary rather than being implied by cross-compilation.

@besmpl
besmpl force-pushed the besmpl/android-arm64-bionic branch 2 times, most recently from 2524e33 to 8ccaae7 Compare July 15, 2026 18:09
@besmpl
besmpl marked this pull request as ready for review July 16, 2026 09:04
@besmpl
besmpl requested a review from kolkov as a code owner July 16, 2026 09:04
@besmpl

besmpl commented Jul 19, 2026

Copy link
Copy Markdown
Contributor Author

@kolkov — the only missing readiness signal here is approval of the fork workflow run: https://github.com/go-webgpu/goffi/actions/runs/29439408858. GitHub currently records it as action_required with zero jobs, so Codecov has no head or patch report to evaluate.

As a preflight at exact head 8ccaae72d877a7af0af4b628bf86e92536e27d88, I reran the Codecov-producing Go 1.25.12 CGO_ENABLED=0 coverage command for ./ffi ./types; it passes at 87.6% total coverage (the current base is 84.47%). Could you please approve the existing run? I will address any real CI or Codecov finding immediately once the authoritative hosted report exists.

@codecov

codecov Bot commented Jul 20, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@kolkov kolkov left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for the delay reviewing this — we've been through the errno v0.6.0 release and the stack-move fix from @tie in parallel. Read through the full diff, ran the CI (15/15 green including both Android jobs), and studied the downstream context in wgpu#268.

The quality here is outstanding. The four-argument _cgo_init matching asm_arm64.s, the Bionic sigset_t difference (8 bytes vs glibc 128 — would silently corrupt pthread_sigmask), the dlerror-within-cgocall thread-locality capture, and the ELF rejection gates in the check script are all things that show deep runtime source knowledge. The fakecgo work goes beyond what purego has done for Android — they only support CGO_ENABLED=1 there.

A couple of points before we merge:

1. runtime.iscgo on Android CGO_ENABLED=0

callbacks.go and iscgo.go exclude android from their build tags, so runtime.iscgo stays false. I assume this is intentional since callbacks are rejected — but iscgo affects several runtime paths beyond callbacks. Can you confirm you've traced through what iscgo=false means for the outbound cgocall path you're using?

2. Exported RTLD constants

ffi/dl_android.go exports RTLD_NOW, RTLD_LOCAL, RTLD_NODELETE from the ffi package. Other platform loaders keep these internal. Is there a use case for callers passing custom flags, or should these be internal with LoadLibrary applying them automatically?

3. Rebase needed — purego_goffi_ rename landed

We just merged #63 which renames all purego_ dynamic imports to goffi_ across internal/fakecgo/ and updates the copyright headers to dual Ebitengine + GoGPU attribution. Your commit b1503fc touches gen.go, symbols_linux.go, and trampolines_stubs.s which will conflict — you'll need a rebase on current main and resolve by keeping goffi_ prefix. Your 4 new Android files (android_dl.go, android_dl_stubs_arm64.s, symbols_android_imports.go, trampolines_stubs_android.s) should also switch to goffi_ prefix.

4. x_cgo_inittls diagnostics

if tlsg == nil || *tlsg != androidTLSGOffset {
    androidFatal("fakecgo: Android runtime.tls_g offset mismatch")
}

Two different failure modes produce the same message: tlsg == nil means the runtime didn't pass the pointer at all (startup sequence issue), while *tlsg != 16 means the TLS slot offset changed (Go ABI drift). On a device without a debugger attached, this fatal is the only diagnostic you get. Worth splitting into two distinct messages? You know the Android startup path better — curious what you think.

Everything else — build tags, assembly, errno routing, callback rejection, CI matrix — looks solid. Happy to merge as guarded preview once we align on these and the rebase is done. Physical device validation can happen through wgpu#268 post-merge.

@kolkov

kolkov commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

One more thing — once this lands, would you be open to being added to .github/CODEOWNERS for the Android paths (*android* across ffi/, internal/dl/, internal/fakecgo/)? Given you've built the entire Bionic layer and have the NDK + device setup, it makes sense to have you as the reviewer for any future Android changes. No pressure — just want to know if that kind of ongoing involvement works for you.

besmpl added 4 commits July 21, 2026 09:01
Document and assert the runtime.iscgo wiring selected by Android's implicit linux build tag, keep RTLD policy internal, split TLS startup diagnostics, and align all Android fakecgo imports with the goffi_ prefix introduced by go-webgpu#63.
@besmpl
besmpl force-pushed the besmpl/android-arm64-bionic branch from 8ccaae7 to a8a33c7 Compare July 21, 2026 06:11
@besmpl

besmpl commented Jul 21, 2026

Copy link
Copy Markdown
Contributor Author

Thank you for the thorough review.

The subtle part of point 1 is that Go defines GOOS=android to also satisfy the linux build term, so iscgo.go, callbacks.go, and setenv.go were already selected and runtime.iscgo was already true. I traced the resulting runtime paths through cgocall, M/thread creation, TLS, signals, traceback state, and extra-M setup. The required fakecgo hooks are present. I added explicit source-selection gates, runtime-wiring assertions, and documentation so this is no longer implicit. Public Android callbacks remain rejected independently.

I also removed the exported RTLD constants, rebased onto #63 with goffi_ imports and updated attribution, and split the two TLS failure diagnostics. The complete Go 1.25.12/1.26.5 × cgo0/cgo1 NDK r29 matrix passes locally.

And yes—absolutely, I’d be happy to be added as CODEOWNER for the Android paths and help review and maintain future Android changes.

@kolkov kolkov left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All four review points addressed cleanly. Build tags, goffi_ naming, iscgo assertions, RTLD internalization, and split diagnostics verified. LGTM as guarded preview.

@kolkov
kolkov merged commit 79e912c into go-webgpu:main Jul 21, 2026
15 checks passed
@kolkov

kolkov commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

Merged and released as v0.6.1. You're now in .github/CODEOWNERS for the Android paths — PRs touching *android* files will request your review automatically. Welcome aboard.

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