# jre27-android-arm64

`jre27-android-arm64.tar.xz` is a Java 27 runtime for Android on arm64 (aarch64, bionic). It's meant to be imported into Pojav-family Minecraft launchers (Amethyst, PojavLauncher and forks) as a custom runtime. It's packaged the same way as AngelAuraMC's `jre25-android-arm64.tar.xz`.

- sha256: `8df6e5fea29149e0637ca7fceccd17f06a4376b6dfaf6b35f9d93c4de6067b46`
- Version: `openjdk version "27" 2026-09-15`, `OpenJDK Android Runtime Environment (build 27+35)`, `OpenJDK 64-Bit Server VM (build 27+35)`
- `release`: `JAVA_VERSION="27"`, `JAVA_RUNTIME_VERSION="27+35"`, `JAVA_VERSION_DATE="2026-09-15"`, `OS_ARCH="aarch64"`, `SOURCE=".:git:815ff4dc327f+"`

## Note on "early access"
JDK 27 is not EA anymore. It reached GA on 2026-09-15, and openjdk/jdk `master` is already JDK 28 (tag `jdk-28+17`, GA date 2027-03-23). This runtime is built from the **GA tag**, not a snapshot:

- Source: https://github.com/openjdk/jdk27u tag `jdk-27-ga` (= `jdk-27+35`), commit `815ff4dc327fe17f2433c7d115a5a503af10f3c4`

When this was built (2026-09-27), no trustworthy prebuilt Android JRE 26 or 27 was available. AngelAuraMC publishes only jre8/17/21/25, FCL and Zalith ship 25 at most, and MojoLauncher's rolling release stops at 25. The only JRE 26 found was a one-star personal repo (HolySnaketz/OpenJDK26-Android), so it wasn't used.

## Layout (same as the AngelAuraMC jre25 reference)
- `bin/`: java, javac, keytool, jfr, jhsdb, jwebserver, rmiregistry, serialver
- `conf/`
- `legal/`
- `release`
- `lib/`
  - `modules`
  - `server/libjvm.so`
  - `libfreetype.so`, fonts, fontconfig
  - `libc++_shared.so` in both `lib/` and `lib/server/`, taken from NDK r27b (the NDK used for the build)
  - a stub `libawt_xawt.so`

The jlink module set matches the jre25 reference's `MODULES` line, minus two modules that JDK 27 no longer has: `jdk.jsobject` and `jdk.internal.vm.ci` (JVMCI).

Compared with the jre25 reference, these are missing, and none of them exist in JDK 27 upstream:
- `bin/jrunscript`
- `conf/sdp/`
- `lib/libjaas.so`

## How it was built
Work dir: `/root/jre27-build`. The build scripts are the `judge/buildjre17-21-25` branch of https://github.com/AngelAuraMC/angelauramc-openjdk-build (the scripts behind their jre25), with local commit `ebec68a` on branch `jre27`. That commit is also saved as `jre27-build-src/0001-*.patch`.

- Toolchain:
  - Android NDK r27b (clang 18), API 21, `--openjdk-target=aarch64-linux-android`
  - headless, server VM, release build
  - freetype 2.10.0
  - boot JDK: Temurin 27+35
  - 43-core host, about 10 minutes
- Configure flags: `--with-version-pre= --with-version-build=35 --with-version-opt=`, so the version string is a plain `27+35`.
- Patches: `jre27-build-src/jdk27u_android.diff`, which applies cleanly to `jdk-27-ga`. It's AngelAuraMC's `jdk25u_android.diff` rebased onto 27, plus:
  - `os::jvm_path` has moved to `os_posix.cpp` in 27, so the Android `/proc/self/maps` libjvm path lookup was moved there. `SYS_gettid` is defined for aarch64.
  - HotSpot's new forbidden-function declarations: bionic headers don't declare libc functions `noexcept`, so `FORBIDDEN_FUNCTION_COND_NOEXCEPT_noexcept` is made empty on Android.
  - The `getifaddrs` shim in `os_perf_linux.cpp` was re-applied and adjusted for the new `FREE_C_HEAP_ARRAY(ptr)` API. The ZGC NUMA workaround was re-applied too.
  - JDK 27's `ProcessImpl_md.c` now uses `posix_spawn_file_actions_init` and `posix_spawn_file_actions_adddup2`. Bionic only has these from API 28, so the bundled compat `posix_spawn` gained a bionic-ABI-compatible dup2 file-actions implementation. This is what `Runtime.exec` and `ProcessBuilder` use.
  - `libtinyiconv` is compiled into `libinstrument` and `libjdwp` (bionic has no `iconv` below API 28).
  - `libsaproc` is skipped because bionic lacks `prstatus_t`. The jre25 builds skip it as well.
  - Two fixes taken from FCL's jre25 patch:
    - `PRODUCT_SUFFIX="Android Runtime Environment"`, which Distant Horizons checks for
    - `statx` is disabled on Android, because class loading broke on old kernels
  - The junk `launcher.properties` rename hunk in the jre25 diff was dropped.
- `libawt_xawt.so` is rebuilt from `jre27-build-src/awt_xawt_stub.c`. It's the same 34 no-op JNI exports as the stub in the jre25 reference, and it links against `libawt_headless.so`.
- Rebuild: `run.sh` runs configure and the build. `pack.sh` does the jlink and tar steps; it needs the cross build's `buildjdk/jdk/bin/jlink` on `PATH`, because Temurin's jlink rejects the different vendor string. After that, add `libc++_shared.so` and the xawt stub, then tar `bin conf legal lib release` without a `./` prefix.

## Verification
- `file`: `bin/java` and `lib/server/libjvm.so` are `ELF 64-bit LSB shared object, ARM aarch64`, with interpreter `/system/bin/linker64`.
- `release` reads `JAVA_VERSION="27"`.
- The build's own x86_64 build JDK, built from the same patched sources, reports `OpenJDK Android Runtime Environment (build 27+35)`.
- qemu-user (`qemu-aarch64-static`) with the bionic userland from the Android 9 (API 28) arm64 emulator image:
  - The Android linker loads the launcher and libjli.
  - It then aborts with `pthread_create failed: couldn't mprotect PROT_NONE 0-byte stack guard region` and a qemu TCG assertion.
  - The AngelAuraMC jre25 reference fails in exactly the same way, so this is a limit of qemu-user on this (gVisor) host, not of the build.
  - `java -version` has **not** actually been executed on aarch64.

## Caveats
- **Untested on a real device.** It hasn't been run in Amethyst or Pojav or on real Android hardware. Test it with a Java 27 capable Minecraft version or modpack before relying on it.
- The runtime links libc++ statically, so the bundled `libc++_shared.so` is only there for layout parity with the reference.
- The `posix_spawn` file-actions shim is new code; nothing like it was in the jre25 patch set. If launching subprocesses fails (for example mod installers that shell out), start there. A fallback is `-Djdk.lang.Process.launchMechanism=FORK`.
- Headless AWT only, as in all Pojav runtimes.
- Only arm64 was built. arm32 isn't supported by JDK 25 and later, and x86_64 wasn't requested.
