From 09a331be3646bacdc53a6177a72f368e6ecd3e5d Mon Sep 17 00:00:00 2001 From: lcy Date: Sun, 18 Oct 2026 10:45:08 +0800 Subject: [PATCH 1/3] fix(runtime): build proot with a seccomp fork fix so x86_64 can install On x86_64 Android (e.g. the emulator) the local runtime never installed: `apk add` failed with "/bin/sh: can't fork: Function not implemented". Android's app seccomp policy only allows fork(2) on 32-bit ABIs, musl calls SYS_fork directly on x86_64, and PRoot's SIGSYS handler answers unknown syscalls with ENOSYS. arm64 has no fork(2) and is unaffected. Carry the PRoot change proposed upstream (termux/proot#415) as a termux-packages recipe patch that rewrites fork(2) into clone(SIGCHLD, 0, 0, 0, 0), and build the github release APKs from the source-built native payload too, so they ship the patched proot rather than the Termux mirror prebuilt. The release runtime-asset cache gets its own key so a mirror-derived payload is never restored there, and the native source build job checks that the patch reached the proot source. Verified on the Android 15 x86_64 emulator: with the patched proot the app's setup installs the runtime and `opencode serve` comes up. --- .github/workflows/native-source-libs.yml | 5 +++ .github/workflows/release.yml | 20 +++++---- .../proot-seccomp-fork-as-clone.patch | 43 +++++++++++++++++++ scripts/build_android_runtime_native_debs.sh | 11 +++++ 4 files changed, 71 insertions(+), 8 deletions(-) create mode 100644 runtime_tools/termux-packaging-recipes/proot-seccomp-fork-as-clone.patch diff --git a/.github/workflows/native-source-libs.yml b/.github/workflows/native-source-libs.yml index e96c8d8d6..aabc6db2d 100644 --- a/.github/workflows/native-source-libs.yml +++ b/.github/workflows/native-source-libs.yml @@ -37,6 +37,11 @@ jobs: - name: Build Termux native runtime packages from source run: bash scripts/build_android_runtime_native_debs.sh --setup --output-dir build/termux-debs + # termux-packages unpacks each package into $TERMUX_TOPDIR//src (the script's + # default TERMUX_TOPDIR); fail if the proot recipe patch did not end up in that source. + - name: Verify the proot seccomp fork patch was applied + run: grep -q 'case PR_fork:' /tmp/andcode-termux-build/proot/src/src/tracee/seccomp.c + - name: Materialize native libraries from the source-built packages run: | python3 scripts/prepare_android_runtime_assets.py \ diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 6f7f8db09..0ef746a4a 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -52,7 +52,10 @@ jobs: path: | build/generated/runtime-assets build/generated/runtime-jni - key: and-code-runtime-${{ runner.os }}-${{ hashFiles('runtime_tools/termux_assets.lock.json', 'runtime_tools/termux_assets.py', 'scripts/prepare_android_runtime_*.py') }} + # Separate key from the mirror-derived cache used by CI: this job generates the runtime + # assets from the source-built .deb files (see the build step below), and the source + # recipes/script are part of the key so a cached mirror-derived payload is never reused. + key: and-code-runtime-source-${{ runner.os }}-${{ hashFiles('runtime_tools/termux_assets.lock.json', 'runtime_tools/termux_assets.py', 'scripts/prepare_android_runtime_*.py', 'scripts/build_android_runtime_native_debs.sh', 'runtime_tools/termux-packaging-recipes/**') }} - name: Decode release keystore env: @@ -80,19 +83,20 @@ jobs: if [ -z "$GITHUB_CLIENT_ID" ]; then echo "::warning::AND_CODE_GITHUB_CLIENT_ID repo variable is not set - the published APK will have no GitHub sign-in" fi - ./gradlew detekt spotlessCheck :app:lintGithubDebug :app:testGithubDebugUnitTest assembleGithubDebug assembleGithubRelease + # The native runtime payload (proot, libtalloc, libandroid-shmem) is compiled first from + # the pinned Termux recipes with the NDK, so the github APKs carry the source-built proot + # (including the seccomp fork fix in runtime_tools/termux-packaging-recipes/) instead of + # the Termux mirror prebuilts. This must match the fdroiddata recipe + # (srclibs: TermuxPackages@, ndk: r29). + bash scripts/build_android_runtime_native_debs.sh --setup --output-dir build/termux-debs + ./gradlew detekt spotlessCheck :app:lintGithubDebug :app:testGithubDebugUnitTest \ + -Pandcode.sourceNativeLibs=true assembleGithubDebug assembleGithubRelease # Separate invocation, deliberately without GITHUB_CLIENT_ID: this is the same flavor and # signing config F-Droid's own build server produces (gradleprops: andcode.fdroidBuild=true, # no client ID), so this asset is what fdroiddata's Binaries:/AllowedAPKSigningKeys: verify # a reproducible build against - it must be built exactly the way F-Droid builds it. # GITHUB_CLIENT_ID is set at step level above, so it must be unset here explicitly: # otherwise it is baked into BuildConfig and classes.dex no longer matches F-Droid's. - # - # The fdroid APK is built the way F-Droid's build server builds it, including the - # native runtime payload: proot, libtalloc and libandroid-shmem are compiled from - # the pinned Termux recipes with the NDK here so no prebuilt binary is downloaded. - # This must match the fdroiddata recipe (srclibs: TermuxPackages@, ndk: r29). - bash scripts/build_android_runtime_native_debs.sh --setup --output-dir build/termux-debs env -u GITHUB_CLIENT_ID ./gradlew -Pandcode.fdroidBuild=true -Pandcode.sourceNativeLibs=true :app:assembleFdroidRelease - name: Resolve tag diff --git a/runtime_tools/termux-packaging-recipes/proot-seccomp-fork-as-clone.patch b/runtime_tools/termux-packaging-recipes/proot-seccomp-fork-as-clone.patch new file mode 100644 index 000000000..be4ecbe1a --- /dev/null +++ b/runtime_tools/termux-packaging-recipes/proot-seccomp-fork-as-clone.patch @@ -0,0 +1,43 @@ +# Android app seccomp fix for proot: rewrite PR_fork as clone(SIGCHLD, 0, 0, 0, 0). +# +# Why: Android's app seccomp policy only allows the fork(2) syscall on 32-bit ABIs. +# musl on x86_64 calls SYS_fork directly, and PRoot's SIGSYS handler +# (src/tracee/seccomp.c, handle_seccomp_event_common) returns -ENOSYS for unhandled +# syscalls, so `apk add` fails with "/bin/sh: can't fork: Function not implemented". +# fork(2) is equivalent to clone(2) with only SIGCHLD set, on every architecture PRoot +# supports, so the sysnum and argument rewrite below is safe. arm64 has no SYS_fork and +# is unaffected. +# +# Upstream: https://github.com/termux/proot/pull/415 (from the discussion in +# https://github.com/termux/proot/issues/237). +# Remove this patch once the pinned termux/proot version includes an equivalent fix. +# +# Applied with `patch -p1` from the proot source directory (termux_step_patch_package +# applies every *.patch in the package builder directory). Header lines precede the first +# `diff --git` line so patch ignores them. +diff --git a/src/tracee/seccomp.c b/src/tracee/seccomp.c +index 66dfef3..53140e4 100644 +--- a/src/tracee/seccomp.c ++++ b/src/tracee/seccomp.c +@@ -626,6 +626,21 @@ static int handle_seccomp_event_common(Tracee *tracee) + break; + } + ++ case PR_fork: ++ /* Android's app seccomp policy only allows fork(2) on ++ * 32-bit ABIs, yet musl calls it directly on x86_64. ++ * fork(2) is clone(2) with just SIGCHLD and no other ++ * argument, on every architecture PRoot supports (only ++ * the last two arguments are ever swapped). */ ++ set_sysnum(tracee, PR_clone); ++ poke_reg(tracee, SYSARG_1, SIGCHLD); ++ poke_reg(tracee, SYSARG_2, 0); ++ poke_reg(tracee, SYSARG_3, 0); ++ poke_reg(tracee, SYSARG_4, 0); ++ poke_reg(tracee, SYSARG_5, 0); ++ restart_syscall_after_seccomp(tracee); ++ break; ++ + case PR_set_robust_list: + default: + /* Set errno to -ENOSYS */ diff --git a/scripts/build_android_runtime_native_debs.sh b/scripts/build_android_runtime_native_debs.sh index 303e9592c..04971bda3 100755 --- a/scripts/build_android_runtime_native_debs.sh +++ b/scripts/build_android_runtime_native_debs.sh @@ -11,6 +11,9 @@ # # Adapted from gwitko/Conduit's tools/build-local-shell-binaries.sh (same Termux + # NDK approach); the recipe patches are the ones that environment is known to need. +# Besides the termux-packages edits above, the proot recipe gets an extra patch from +# runtime_tools/termux-packaging-recipes/proot-seccomp-fork-as-clone.patch (rewrites SYS_fork +# to clone for the Android app seccomp policy; needed for x86_64 `apk add` to fork). # # Inputs (environment): # TERMUX_PACKAGES_DIR An existing termux-packages checkout (an F-Droid srclib). @@ -132,6 +135,14 @@ patch_setup_ubuntu patch_buildarch patch_toolchain +# PRoot recipe patch (see runtime_tools/termux-packaging-recipes/proot-seccomp-fork-as-clone.patch): +# Android's app seccomp policy only allows fork(2) on 32-bit ABIs, so the x86_64 build needs +# SYS_fork rewritten to clone(). termux_step_patch_package applies every *.patch in the package +# builder directory, so copy it there. The file is untracked, so cp -f simply overwrites it on +# re-runs (checkout -f above resets only tracked files). +cp -f "$REPO_ROOT/runtime_tools/termux-packaging-recipes/proot-seccomp-fork-as-clone.patch" \ + "$TERMUX_PACKAGES_DIR/packages/proot/" + if [ "$SETUP_UBUNTU" -eq 1 ]; then termux_env bash "$TERMUX_PACKAGES_DIR/scripts/setup-ubuntu.sh" fi From 7e931f9941124533e4f1272a465c7034fb12d6d6 Mon Sep 17 00:00:00 2001 From: lcy Date: Sun, 18 Oct 2026 11:03:47 +0800 Subject: [PATCH 2/3] fix(runtime): keep proot 5.1.107.96 in source builds and disclose the patch Source builds used the pinned termux-packages commit's proot recipe, 5.1.107.94, while the lock pins 5.1.107.96, so building the github APKs from source would have downgraded proot. Override the recipe with the mirrored 5.1.107.96 build.sh (the pinned commit can't be bumped: the .96 bump moved to NDK r30). Update the third-party notices, which said release binaries come from the mirror unmodified, to state the source build and the proot modification. --- THIRD_PARTY_NOTICES.md | 28 +++++++++++++------ THIRD_PARTY_SERVICES.md | 2 +- app/src/main/assets/legal/oss_licenses.md | 28 +++++++++++++------ .../assets/legal/third_party_services.ja.md | 2 +- .../main/assets/legal/third_party_services.md | 2 +- docs/RELEASE.md | 4 +++ .../proot-seccomp-fork-as-clone.patch | 5 ++++ .../termux-packaging-recipes/proot.build.sh | 1 + scripts/build_android_runtime_native_debs.sh | 21 ++++++++------ 9 files changed, 64 insertions(+), 29 deletions(-) diff --git a/THIRD_PARTY_NOTICES.md b/THIRD_PARTY_NOTICES.md index e4a528b22..993080117 100644 --- a/THIRD_PARTY_NOTICES.md +++ b/THIRD_PARTY_NOTICES.md @@ -7,13 +7,22 @@ source code.** See [TRADEMARKS.md](TRADEMARKS.md) for trademark notices. ## Bundled native runtime components (PRoot / Termux-derived) -These binaries reach the APK one of two ways. The **github** flavor downloads them from the official -Termux package mirror at build time (pinned by package version and SHA-256 hash of the compiled -`.deb` in [`runtime_tools/termux_assets.lock.json`](runtime_tools/termux_assets.lock.json)). The -**fdroid** flavor compiles the same three Termux packages from source with the Android NDK, from the -pinned `termux-packages` commit declared by the fdroiddata recipe's `srclibs:` (`TermuxPackages`). -Either way they are packaged into the APK so the on-device Linux runtime can start, and AndCode does -not patch or modify these packages beyond what Termux's own packaging performs. **Full license text +Release APKs (both the **github** and **fdroid** flavors) build these three packages from source with the +Android NDK r29, using the pinned Termux package recipes: `proot`, `libtalloc` and `libandroid-shmem` +are compiled from the `termux-packages` commit pinned in +[`scripts/build_android_runtime_native_debs.sh`](scripts/build_android_runtime_native_debs.sh). The +`proot` recipe is overridden to the 5.1.107.96 build in +[`runtime_tools/termux-packaging-recipes/proot.build.sh`](runtime_tools/termux-packaging-recipes/proot.build.sh). +Local and CI developer builds instead download the prebuilt packages from the official Termux package +mirror, pinned by package version and SHA-256 hash of the compiled `.deb` in +[`runtime_tools/termux_assets.lock.json`](runtime_tools/termux_assets.lock.json). Either way they are +packaged into the APK so the on-device Linux runtime can start. AndCode applies one modification to +`proot`: [`proot-seccomp-fork-as-clone.patch`](runtime_tools/termux-packaging-recipes/proot-seccomp-fork-as-clone.patch), +which makes PRoot run `fork(2)` as `clone(SIGCHLD)` when Android's app seccomp policy rejects `fork` +(needed on x86_64, where musl calls `SYS_fork` directly). It is proposed upstream as +[termux/proot#415](https://github.com/termux/proot/pull/415). This paragraph is the GPL-2.0 §2(a) +notice of that modification for the `proot` binary. Packages other than `proot` are not modified +beyond Termux's own packaging. **Full license text for each of GPL-2.0, GPL-3.0 (which LGPL-3.0 incorporates by reference), LGPL-3.0, and the BSD-3-Clause text used by `libandroid-shmem` is bundled verbatim, unmodified, in [`THIRD_PARTY_LICENSES/`](THIRD_PARTY_LICENSES/) in this repository and at @@ -25,8 +34,9 @@ BSD-3-Clause text used by `libandroid-shmem` is bundled verbatim, unmodified, in | `libandroid-shmem` | 0.7 | [BSD-3-Clause](THIRD_PARTY_LICENSES/BSD-3-Clause-libandroid-shmem.txt), per [`TERMUX_PKG_LICENSE`](runtime_tools/termux-packaging-recipes/libandroid-shmem.build.sh) and the project's own `LICENSE` file | Copyright (c) 2013 Sergii Pylypenko; Copyright (c) 2017 Fredrik Fornwall | Upstream source archive `v0.7.tar.gz`, SHA-256 `1e5ff8459bc0a8c229dd8a94b27d119987e09ef3414331c2b5ebfff20b98e867` (from [github.com/termux/libandroid-shmem](https://github.com/termux/libandroid-shmem/archive/refs/tags/v0.7.tar.gz), tagged release, not `master`) | | `libtalloc` | 2.5.0 | [LGPL-3.0-or-later](THIRD_PARTY_LICENSES/LGPL-3.0.txt) for the actual runtime library. Termux's own packaging metadata tags the *package* `GPL-3.0` (a coarser, package-level tag), but the shared library source itself (`talloc.c`/`talloc.h`, the only files that become `libtalloc.a`/`libtalloc.so`) carries its own header: *"the following LGPL license applies to the talloc library. This does NOT imply that all of Samba is released under the LGPL"* — version 3 or later. Resolved; no longer `REQUIRES_LICENSE_REVIEW`. | Copyright (C) Andrew Tridgell 2004; Copyright (C) Stefan Metzmacher 2006 | Upstream source archive `talloc-2.5.0.tar.gz`, SHA-256 `912afa237510ae542a7733998eb18a12bcda35ab6729c8e2ddb43e8d0ebab007` (from [samba.org/ftp/talloc](https://www.samba.org/ftp/talloc/talloc-2.5.0.tar.gz), versioned release path, not a mutable branch) | -The fdroid flavor compiles all three from the pinned `TermuxPackages` commit, which can lag the -mirror by a version or two (currently `proot` 5.1.107.94, `libtalloc` 2.4.3, `libandroid-shmem` 0.7). +The source build compiles `libtalloc` and `libandroid-shmem` from the pinned `TermuxPackages` commit, +which can lag the mirror by a version or two (currently `libtalloc` 2.4.3, `libandroid-shmem` 0.7). +Its `proot` recipe is overridden to 5.1.107.96 as described above. **Packaging recipes, mirrored (not just linked):** the exact `TERMUX_PKG_*` build recipe used for each package above — the thing that actually produces the `.deb` pinned by hash in diff --git a/THIRD_PARTY_SERVICES.md b/THIRD_PARTY_SERVICES.md index e5eba6a2d..c839f93b1 100644 --- a/THIRD_PARTY_SERVICES.md +++ b/THIRD_PARTY_SERVICES.md @@ -17,7 +17,7 @@ Claude Code, Antigravity, and OpenCode specifically. | **MCP servers you configure** | Optional tool/context servers you add for an agent to call | Depends on the server (local command or remote URL you provide) | The agent CLI connects to the server you configured | Any server credentials go wherever you configure them (e.g., server-side env vars); AndCode does not manage server-side secrets | No | Whichever terms the specific MCP server operator sets | Remove the server in **Settings → MCP** | Third-party servers you choose to add; not affiliated with AndCode | | **Alpine Linux** (`dl-cdn.alpinelinux.org`) | Minimal Linux root filesystem the on-device runtime runs in | N/A (unauthenticated download) | The app downloads the official Alpine minirootfs archive over HTTPS | N/A | No | [Alpine Linux license terms](https://alpinelinux.org/) (per-package) | Delete the local runtime | Independent open-source project | | **Debian** (`deb.debian.org`, `security.debian.org`) | Bookworm root filesystem used only for the glibc-dependent Antigravity CLI | N/A (unauthenticated `apt` mirrors) | `apt` inside the Debian rootfs fetches packages over the configured mirrors | N/A | No | [Debian's licenses](https://www.debian.org/legal/) (per-package) | Delete the local runtime | Independent open-source project | -| **Termux package mirror** (`packages.termux.dev`) | Source of the `proot`, `libandroid-shmem`, and `libtalloc` binaries bundled into the APK at build time | N/A (build-time download, pinned by hash) | Build machine only, not the end-user's device at runtime | N/A | No | Upstream licenses vary — see [THIRD_PARTY_NOTICES.md](THIRD_PARTY_NOTICES.md) | N/A (bundled at build time) | Independent open-source project | +| **Termux package sources** (`github.com/termux/termux-packages`, and the `packages.termux.dev` mirror for local/CI dev builds) | Build recipes and source for the `proot`, `libandroid-shmem`, and `libtalloc` binaries bundled into the APK at build time (release APKs build them from source; dev builds download prebuilt packages) | N/A (build-time fetch; source pinned by commit, dev-build packages pinned by hash) | Build machine only, not the end-user's device at runtime | N/A | No | Upstream licenses vary — see [THIRD_PARTY_NOTICES.md](THIRD_PARTY_NOTICES.md) | N/A (bundled at build time) | Independent open-source project | | **Firebase Crashlytics** (Google) | Crash and non-fatal error reporting in release builds | N/A (app-level Firebase project, no end-user login) | The app sends crash reports and small diagnostic breadcrumbs directly to Firebase; custom log lines/keys AndCode's own code adds are redacted on a best-effort basis (see PRIVACY.md §7), but automatic fatal-crash collection by the Crashlytics SDK itself is not routed through that redaction | N/A (no user credential; app-level Firebase config) | This *is* a Google-operated collection service, not an AndCode server | [Firebase Terms of Service](https://firebase.google.com/terms) / [Google Privacy Policy](https://policies.google.com/privacy) | Disabled automatically in debug builds; release collection follows the app's diagnostics policy | Independent Google service; not affiliated with the AI-agent integrations above | | **Firebase Analytics** (Google) | Opt-in anonymous app-open/session and runtime outcome metrics | N/A (app-level Firebase project, no end-user login) | The Firebase SDK sends telemetry directly to Firebase; AndCode excludes prompts, code, responses, tokens, and workspace paths | N/A (no user credential; app-level Firebase config) | This *is* a Google-operated collection service, not an AndCode server | [Firebase Terms of Service](https://firebase.google.com/terms) / [Google Privacy Policy](https://policies.google.com/privacy) | Disabled by default; enable or withdraw consent in Settings | Independent Google service; not affiliated with the AI-agent integrations above | diff --git a/app/src/main/assets/legal/oss_licenses.md b/app/src/main/assets/legal/oss_licenses.md index e4a528b22..993080117 100644 --- a/app/src/main/assets/legal/oss_licenses.md +++ b/app/src/main/assets/legal/oss_licenses.md @@ -7,13 +7,22 @@ source code.** See [TRADEMARKS.md](TRADEMARKS.md) for trademark notices. ## Bundled native runtime components (PRoot / Termux-derived) -These binaries reach the APK one of two ways. The **github** flavor downloads them from the official -Termux package mirror at build time (pinned by package version and SHA-256 hash of the compiled -`.deb` in [`runtime_tools/termux_assets.lock.json`](runtime_tools/termux_assets.lock.json)). The -**fdroid** flavor compiles the same three Termux packages from source with the Android NDK, from the -pinned `termux-packages` commit declared by the fdroiddata recipe's `srclibs:` (`TermuxPackages`). -Either way they are packaged into the APK so the on-device Linux runtime can start, and AndCode does -not patch or modify these packages beyond what Termux's own packaging performs. **Full license text +Release APKs (both the **github** and **fdroid** flavors) build these three packages from source with the +Android NDK r29, using the pinned Termux package recipes: `proot`, `libtalloc` and `libandroid-shmem` +are compiled from the `termux-packages` commit pinned in +[`scripts/build_android_runtime_native_debs.sh`](scripts/build_android_runtime_native_debs.sh). The +`proot` recipe is overridden to the 5.1.107.96 build in +[`runtime_tools/termux-packaging-recipes/proot.build.sh`](runtime_tools/termux-packaging-recipes/proot.build.sh). +Local and CI developer builds instead download the prebuilt packages from the official Termux package +mirror, pinned by package version and SHA-256 hash of the compiled `.deb` in +[`runtime_tools/termux_assets.lock.json`](runtime_tools/termux_assets.lock.json). Either way they are +packaged into the APK so the on-device Linux runtime can start. AndCode applies one modification to +`proot`: [`proot-seccomp-fork-as-clone.patch`](runtime_tools/termux-packaging-recipes/proot-seccomp-fork-as-clone.patch), +which makes PRoot run `fork(2)` as `clone(SIGCHLD)` when Android's app seccomp policy rejects `fork` +(needed on x86_64, where musl calls `SYS_fork` directly). It is proposed upstream as +[termux/proot#415](https://github.com/termux/proot/pull/415). This paragraph is the GPL-2.0 §2(a) +notice of that modification for the `proot` binary. Packages other than `proot` are not modified +beyond Termux's own packaging. **Full license text for each of GPL-2.0, GPL-3.0 (which LGPL-3.0 incorporates by reference), LGPL-3.0, and the BSD-3-Clause text used by `libandroid-shmem` is bundled verbatim, unmodified, in [`THIRD_PARTY_LICENSES/`](THIRD_PARTY_LICENSES/) in this repository and at @@ -25,8 +34,9 @@ BSD-3-Clause text used by `libandroid-shmem` is bundled verbatim, unmodified, in | `libandroid-shmem` | 0.7 | [BSD-3-Clause](THIRD_PARTY_LICENSES/BSD-3-Clause-libandroid-shmem.txt), per [`TERMUX_PKG_LICENSE`](runtime_tools/termux-packaging-recipes/libandroid-shmem.build.sh) and the project's own `LICENSE` file | Copyright (c) 2013 Sergii Pylypenko; Copyright (c) 2017 Fredrik Fornwall | Upstream source archive `v0.7.tar.gz`, SHA-256 `1e5ff8459bc0a8c229dd8a94b27d119987e09ef3414331c2b5ebfff20b98e867` (from [github.com/termux/libandroid-shmem](https://github.com/termux/libandroid-shmem/archive/refs/tags/v0.7.tar.gz), tagged release, not `master`) | | `libtalloc` | 2.5.0 | [LGPL-3.0-or-later](THIRD_PARTY_LICENSES/LGPL-3.0.txt) for the actual runtime library. Termux's own packaging metadata tags the *package* `GPL-3.0` (a coarser, package-level tag), but the shared library source itself (`talloc.c`/`talloc.h`, the only files that become `libtalloc.a`/`libtalloc.so`) carries its own header: *"the following LGPL license applies to the talloc library. This does NOT imply that all of Samba is released under the LGPL"* — version 3 or later. Resolved; no longer `REQUIRES_LICENSE_REVIEW`. | Copyright (C) Andrew Tridgell 2004; Copyright (C) Stefan Metzmacher 2006 | Upstream source archive `talloc-2.5.0.tar.gz`, SHA-256 `912afa237510ae542a7733998eb18a12bcda35ab6729c8e2ddb43e8d0ebab007` (from [samba.org/ftp/talloc](https://www.samba.org/ftp/talloc/talloc-2.5.0.tar.gz), versioned release path, not a mutable branch) | -The fdroid flavor compiles all three from the pinned `TermuxPackages` commit, which can lag the -mirror by a version or two (currently `proot` 5.1.107.94, `libtalloc` 2.4.3, `libandroid-shmem` 0.7). +The source build compiles `libtalloc` and `libandroid-shmem` from the pinned `TermuxPackages` commit, +which can lag the mirror by a version or two (currently `libtalloc` 2.4.3, `libandroid-shmem` 0.7). +Its `proot` recipe is overridden to 5.1.107.96 as described above. **Packaging recipes, mirrored (not just linked):** the exact `TERMUX_PKG_*` build recipe used for each package above — the thing that actually produces the `.deb` pinned by hash in diff --git a/app/src/main/assets/legal/third_party_services.ja.md b/app/src/main/assets/legal/third_party_services.ja.md index 3e9fdf6f6..191d18fdd 100644 --- a/app/src/main/assets/legal/third_party_services.ja.md +++ b/app/src/main/assets/legal/third_party_services.ja.md @@ -13,7 +13,7 @@ AndCodeは以下の第三者サービスと連携します。AndCodeは利用者 | **設定したMCPサーバー** | エージェントが呼び出す任意のツール/コンテキストサーバー | サーバーによる(利用者が指定するローカルコマンドまたはリモートURL) | エージェントCLIが設定したサーバーへ接続 | サーバー側の資格情報は、設定した場所(例:サーバー側の環境変数)に依存。AndCodeはサーバー側の機密情報を管理しません | いいえ | 各MCPサーバー運営者が定める規約 | **設定 → MCP**でサーバーを削除 | 利用者が選んで追加する第三者サーバー。AndCodeとは提携していません | | **Alpine Linux**(`dl-cdn.alpinelinux.org`) | 端末内ランタイムが動作する最小Linuxルートファイルシステム | 該当なし(認証不要のダウンロード) | アプリが公式Alpine minirootfsアーカイブをHTTPS経由でダウンロード | 該当なし | いいえ | [Alpine Linuxのライセンス条件](https://alpinelinux.org/)(パッケージごと) | ローカルランタイムを削除 | 独立したオープンソースプロジェクト | | **Debian**(`deb.debian.org`、`security.debian.org`) | glibcに依存するAntigravity CLI専用のBookworm rootfs | 該当なし(認証不要の`apt`ミラー) | Debian rootfs内の`apt`が、設定されたミラーからパッケージを取得 | 該当なし | いいえ | [Debianのライセンス](https://www.debian.org/legal/)(パッケージごと) | ローカルランタイムを削除 | 独立したオープンソースプロジェクト | -| **Termuxパッケージミラー**(`packages.termux.dev`) | ビルド時にAPKへ同梱される`proot`、`libandroid-shmem`、`libtalloc`バイナリの取得元 | 該当なし(ビルド時のダウンロードで、ハッシュにより固定) | ビルドマシンのみ。実行時にエンドユーザーの端末が通信するわけではない | 該当なし | いいえ | 配布元のライセンスは各種 — [THIRD_PARTY_NOTICES.md](THIRD_PARTY_NOTICES.md)を参照 | 該当なし(ビルド時に同梱) | 独立したオープンソースプロジェクト | +| **Termuxパッケージのソース**(`github.com/termux/termux-packages`、および開発ビルド用の`packages.termux.dev`ミラー) | ビルド時にAPKへ同梱される`proot`、`libandroid-shmem`、`libtalloc`のレシピとソース(リリースAPKはソースからビルド。開発ビルドはビルド済みパッケージをダウンロード) | 該当なし(ビルド時の取得で、ソースはコミットにより、開発ビルドのパッケージはハッシュにより固定) | ビルドマシンのみ。実行時にエンドユーザーの端末が通信するわけではない | 該当なし | いいえ | 配布元のライセンスは各種 — [THIRD_PARTY_NOTICES.md](THIRD_PARTY_NOTICES.md)を参照 | 該当なし(ビルド時に同梱) | 独立したオープンソースプロジェクト | | **Firebase Crashlytics**(Google) | リリースビルドにおけるクラッシュおよび非致命的エラーの報告 | 該当なし(アプリレベルのFirebaseプロジェクトで、エンドユーザーのログインはなし) | アプリがクラッシュレポートと小さな診断情報をFirebaseへ直接送信。AndCode自身のコードが追加するカスタムログ行/キーはベストエフォートでマスキングされる(PRIVACY.md §7参照)が、Crashlytics SDK自身による致命的クラッシュの自動収集はこのマスキング処理を経由しない | 該当なし(利用者の資格情報はなし。アプリレベルのFirebase設定のみ) | これはGoogleが運用する収集サービス**そのもの**であり、AndCodeのサーバーではありません | [Firebaseの利用規約](https://firebase.google.com/terms) / [Googleのプライバシーポリシー](https://policies.google.com/privacy) | デバッグビルドでは自動的に無効。現時点でリリースビルドにおいて利用者ごとの切り替えはできません | 独立したGoogleのサービス。上記のAIエージェント連携とは無関係 | ## OpenCodeの資格情報経路 diff --git a/app/src/main/assets/legal/third_party_services.md b/app/src/main/assets/legal/third_party_services.md index e5eba6a2d..c839f93b1 100644 --- a/app/src/main/assets/legal/third_party_services.md +++ b/app/src/main/assets/legal/third_party_services.md @@ -17,7 +17,7 @@ Claude Code, Antigravity, and OpenCode specifically. | **MCP servers you configure** | Optional tool/context servers you add for an agent to call | Depends on the server (local command or remote URL you provide) | The agent CLI connects to the server you configured | Any server credentials go wherever you configure them (e.g., server-side env vars); AndCode does not manage server-side secrets | No | Whichever terms the specific MCP server operator sets | Remove the server in **Settings → MCP** | Third-party servers you choose to add; not affiliated with AndCode | | **Alpine Linux** (`dl-cdn.alpinelinux.org`) | Minimal Linux root filesystem the on-device runtime runs in | N/A (unauthenticated download) | The app downloads the official Alpine minirootfs archive over HTTPS | N/A | No | [Alpine Linux license terms](https://alpinelinux.org/) (per-package) | Delete the local runtime | Independent open-source project | | **Debian** (`deb.debian.org`, `security.debian.org`) | Bookworm root filesystem used only for the glibc-dependent Antigravity CLI | N/A (unauthenticated `apt` mirrors) | `apt` inside the Debian rootfs fetches packages over the configured mirrors | N/A | No | [Debian's licenses](https://www.debian.org/legal/) (per-package) | Delete the local runtime | Independent open-source project | -| **Termux package mirror** (`packages.termux.dev`) | Source of the `proot`, `libandroid-shmem`, and `libtalloc` binaries bundled into the APK at build time | N/A (build-time download, pinned by hash) | Build machine only, not the end-user's device at runtime | N/A | No | Upstream licenses vary — see [THIRD_PARTY_NOTICES.md](THIRD_PARTY_NOTICES.md) | N/A (bundled at build time) | Independent open-source project | +| **Termux package sources** (`github.com/termux/termux-packages`, and the `packages.termux.dev` mirror for local/CI dev builds) | Build recipes and source for the `proot`, `libandroid-shmem`, and `libtalloc` binaries bundled into the APK at build time (release APKs build them from source; dev builds download prebuilt packages) | N/A (build-time fetch; source pinned by commit, dev-build packages pinned by hash) | Build machine only, not the end-user's device at runtime | N/A | No | Upstream licenses vary — see [THIRD_PARTY_NOTICES.md](THIRD_PARTY_NOTICES.md) | N/A (bundled at build time) | Independent open-source project | | **Firebase Crashlytics** (Google) | Crash and non-fatal error reporting in release builds | N/A (app-level Firebase project, no end-user login) | The app sends crash reports and small diagnostic breadcrumbs directly to Firebase; custom log lines/keys AndCode's own code adds are redacted on a best-effort basis (see PRIVACY.md §7), but automatic fatal-crash collection by the Crashlytics SDK itself is not routed through that redaction | N/A (no user credential; app-level Firebase config) | This *is* a Google-operated collection service, not an AndCode server | [Firebase Terms of Service](https://firebase.google.com/terms) / [Google Privacy Policy](https://policies.google.com/privacy) | Disabled automatically in debug builds; release collection follows the app's diagnostics policy | Independent Google service; not affiliated with the AI-agent integrations above | | **Firebase Analytics** (Google) | Opt-in anonymous app-open/session and runtime outcome metrics | N/A (app-level Firebase project, no end-user login) | The Firebase SDK sends telemetry directly to Firebase; AndCode excludes prompts, code, responses, tokens, and workspace paths | N/A (no user credential; app-level Firebase config) | This *is* a Google-operated collection service, not an AndCode server | [Firebase Terms of Service](https://firebase.google.com/terms) / [Google Privacy Policy](https://policies.google.com/privacy) | Disabled by default; enable or withdraw consent in Settings | Independent Google service; not affiliated with the AI-agent integrations above | diff --git a/docs/RELEASE.md b/docs/RELEASE.md index 4941f9b7b..c34224908 100644 --- a/docs/RELEASE.md +++ b/docs/RELEASE.md @@ -124,6 +124,10 @@ NDK is needed). `Pandcode.fdroidBuild=true` additionally skips applying the (they process `google-services.json` project-wide regardless of flavor, so leaving them applied would still embed inert Google project identifiers in the fdroid build). +The Release workflow now builds the `github` release APKs from the same source-built native payload +(with the `proot` recipe override and the seccomp fork patch), not from the Termux mirror prebuilts. +Local and CI dev builds still use the mirror path. + Submitting to the official catalog means opening a merge request against [fdroiddata](https://gitlab.com/fdroid/fdroiddata). This has been done: [!48005](https://gitlab.com/fdroid/fdroiddata/-/merge_requests/48005). The diff --git a/runtime_tools/termux-packaging-recipes/proot-seccomp-fork-as-clone.patch b/runtime_tools/termux-packaging-recipes/proot-seccomp-fork-as-clone.patch index be4ecbe1a..d10b19e4a 100644 --- a/runtime_tools/termux-packaging-recipes/proot-seccomp-fork-as-clone.patch +++ b/runtime_tools/termux-packaging-recipes/proot-seccomp-fork-as-clone.patch @@ -8,6 +8,11 @@ # supports, so the sysnum and argument rewrite below is safe. arm64 has no SYS_fork and # is unaffected. # +# Register note: only the parent's registers are restored after the seccomp rewrite, so the +# child of the rewritten clone starts with rdi=SIGCHLD and rsi/rdx/r10/r8 zeroed. musl's x86_64 +# _Fork only reads %rax after the syscall, and glibc uses clone(2) directly, so this is harmless +# in practice. +# # Upstream: https://github.com/termux/proot/pull/415 (from the discussion in # https://github.com/termux/proot/issues/237). # Remove this patch once the pinned termux/proot version includes an equivalent fix. diff --git a/runtime_tools/termux-packaging-recipes/proot.build.sh b/runtime_tools/termux-packaging-recipes/proot.build.sh index ae054d3b7..e981885f8 100644 --- a/runtime_tools/termux-packaging-recipes/proot.build.sh +++ b/runtime_tools/termux-packaging-recipes/proot.build.sh @@ -6,6 +6,7 @@ # runtime_tools/termux_assets.lock.json. # # Contributor: @michalbednarski +# Note: scripts/build_android_runtime_native_debs.sh also copies this file over packages/proot/build.sh of the pinned termux-packages commit (which still has 5.1.107.94) for source builds. TERMUX_PKG_HOMEPAGE=https://proot-me.github.io/ TERMUX_PKG_DESCRIPTION="Emulate chroot, bind mount and binfmt_misc for non-root users" TERMUX_PKG_LICENSE="GPL-2.0" diff --git a/scripts/build_android_runtime_native_debs.sh b/scripts/build_android_runtime_native_debs.sh index 04971bda3..f2d866c29 100755 --- a/scripts/build_android_runtime_native_debs.sh +++ b/scripts/build_android_runtime_native_debs.sh @@ -11,9 +11,9 @@ # # Adapted from gwitko/Conduit's tools/build-local-shell-binaries.sh (same Termux + # NDK approach); the recipe patches are the ones that environment is known to need. -# Besides the termux-packages edits above, the proot recipe gets an extra patch from -# runtime_tools/termux-packaging-recipes/proot-seccomp-fork-as-clone.patch (rewrites SYS_fork -# to clone for the Android app seccomp policy; needed for x86_64 `apk add` to fork). +# The proot recipe is overridden with runtime_tools/termux-packaging-recipes/proot.build.sh +# (5.1.107.96, the lock-pinned version) and gets one extra patch, +# proot-seccomp-fork-as-clone.patch, which is needed for x86_64 `apk add` to fork. # # Inputs (environment): # TERMUX_PACKAGES_DIR An existing termux-packages checkout (an F-Droid srclib). @@ -135,11 +135,16 @@ patch_setup_ubuntu patch_buildarch patch_toolchain -# PRoot recipe patch (see runtime_tools/termux-packaging-recipes/proot-seccomp-fork-as-clone.patch): -# Android's app seccomp policy only allows fork(2) on 32-bit ABIs, so the x86_64 build needs -# SYS_fork rewritten to clone(). termux_step_patch_package applies every *.patch in the package -# builder directory, so copy it there. The file is untracked, so cp -f simply overwrites it on -# re-runs (checkout -f above resets only tracked files). +# PRoot recipe. The pinned termux-packages commit still builds proot 5.1.107.94, but the +# lock-pinned mirror (and so the expected github/fdroid version) is 5.1.107.96. The .96 bump +# (de396619) also moved the toolchain to NDK r30 and removed termux_setup_toolchain_29.sh, so the +# pinned commit cannot simply be bumped. Instead the packages/proot recipe is overridden with the +# mirrored 5.1.107.96 build.sh. The fork patch applies unchanged to both versions because +# src/tracee/seccomp.c is identical in .94 and .96. Stale untracked files are removed first. +# termux_step_patch_package applies every *.patch in the package builder directory. +git -C "$TERMUX_PACKAGES_DIR" clean -fdq -- packages/proot +cp -f "$REPO_ROOT/runtime_tools/termux-packaging-recipes/proot.build.sh" \ + "$TERMUX_PACKAGES_DIR/packages/proot/build.sh" cp -f "$REPO_ROOT/runtime_tools/termux-packaging-recipes/proot-seccomp-fork-as-clone.patch" \ "$TERMUX_PACKAGES_DIR/packages/proot/" From 8e35031b4ffab398f945b83d695cb67bb21c119c Mon Sep 17 00:00:00 2001 From: lcy Date: Sun, 18 Oct 2026 11:05:18 +0800 Subject: [PATCH 3/3] ci(native): check the proot override and patch for both architectures Keep proot.build.sh a verbatim mirror (the note now lives only in the build script). --- .github/workflows/native-source-libs.yml | 17 ++++++++++++----- .../termux-packaging-recipes/proot.build.sh | 1 - 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/.github/workflows/native-source-libs.yml b/.github/workflows/native-source-libs.yml index aabc6db2d..73b53e530 100644 --- a/.github/workflows/native-source-libs.yml +++ b/.github/workflows/native-source-libs.yml @@ -35,12 +35,19 @@ jobs: python-version: "3.11" - name: Build Termux native runtime packages from source - run: bash scripts/build_android_runtime_native_debs.sh --setup --output-dir build/termux-debs + run: | + set -o pipefail + mkdir -p build + bash scripts/build_android_runtime_native_debs.sh --setup --output-dir build/termux-debs \ + 2>&1 | tee build/termux-build.log - # termux-packages unpacks each package into $TERMUX_TOPDIR//src (the script's - # default TERMUX_TOPDIR); fail if the proot recipe patch did not end up in that source. - - name: Verify the proot seccomp fork patch was applied - run: grep -q 'case PR_fork:' /tmp/andcode-termux-build/proot/src/src/tracee/seccomp.c + # The script overrides the pinned commit's proot recipe with the lock-pinned 5.1.107.96 and + # adds the seccomp fork patch; fail if either did not take effect for both architectures. + - name: Verify the proot recipe override and fork patch + run: | + set -euo pipefail + test "$(ls build/termux-debs/*/proot_5.1.107.96_*.deb | wc -l)" -eq 2 + test "$(grep -c 'Applying patch: proot-seccomp-fork-as-clone.patch' build/termux-build.log)" -eq 2 - name: Materialize native libraries from the source-built packages run: | diff --git a/runtime_tools/termux-packaging-recipes/proot.build.sh b/runtime_tools/termux-packaging-recipes/proot.build.sh index e981885f8..ae054d3b7 100644 --- a/runtime_tools/termux-packaging-recipes/proot.build.sh +++ b/runtime_tools/termux-packaging-recipes/proot.build.sh @@ -6,7 +6,6 @@ # runtime_tools/termux_assets.lock.json. # # Contributor: @michalbednarski -# Note: scripts/build_android_runtime_native_debs.sh also copies this file over packages/proot/build.sh of the pinned termux-packages commit (which still has 5.1.107.94) for source builds. TERMUX_PKG_HOMEPAGE=https://proot-me.github.io/ TERMUX_PKG_DESCRIPTION="Emulate chroot, bind mount and binfmt_misc for non-root users" TERMUX_PKG_LICENSE="GPL-2.0"