Skip to content

Android emulator#164

Open
CedricGuillemet wants to merge 25 commits intoBabylonJS:mainfrom
CedricGuillemet:AndroidEmulator
Open

Android emulator#164
CedricGuillemet wants to merge 25 commits intoBabylonJS:mainfrom
CedricGuillemet:AndroidEmulator

Conversation

@CedricGuillemet
Copy link
Copy Markdown
Collaborator

@CedricGuillemet CedricGuillemet commented Apr 20, 2026

Brings back Android Emulator tests.

CedricGuillemet and others added 24 commits April 20, 2026 15:13
- Creates Android AVD with system images stored in scripts/avd_home/
- Auto-detects installed system image ABI (arm64-v8a / x86_64) from SDK
- Uses ANDROID_AVD_HOME consistently for avdmanager + emulator commands
- Compiles hello_world/hello.c with latest NDK clang for detected ABI
- Pushes binary to emulator, runs it, verifies 'hello world' in logcat
- Polls logcat instead of fixed sleep for reliable verification
- Manages emulator lifecycle on fixed port 5554 to avoid killing unrelated instances

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Homebrew's avdmanager wrapper derives the Android SDK root from the
'com.android.sdkmanager.toolsdir' JVM property, which defaults to
its own Homebrew cellar directory and therefore cannot find installed
system images.

Fix: export AVDMANAGER_OPTS and SDKMANAGER_OPTS with toolsdir set to
$ANDROID_SDK/platform-tools so avdmanager computes the correct SDK root
(one level up from platform-tools = the ANDROID_HOME directory).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Three bugs fixed:

1. config.ini image path: Homebrew avdmanager writes image.sysdir.1
   relative to dirname(ANDROID_SDK), producing 'sdk/system-images/...'
   Post-patch strips the spurious 'sdk/' prefix so the emulator resolves
   the path correctly against ANDROID_SDK_ROOT=ANDROID_SDK.

2. set -eo pipefail + adb during boot: adb shell/get-state return non-zero
   transiently while the emulator is still initializing, silently killing
   the script. All adb calls in wait loops now use '|| true' guards.

3. Device online check: replaced 'adb wait-for-device | grep' pipeline
   (fragile under pipefail) with an explicit get-state polling loop that
   also checks emulator process health.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…Logger

- Add scripts/android_unit_tests.sh: end-to-end pipeline that builds the
  UnitTests Android project with gradlew, starts the AVD emulator, deploys
  and runs the instrumented tests, and reports pass/fail.
  Auto-detects the highest installed NDK to override the pinned ndkVersion
  in build.gradle (NDK 23 lacks C++20 support needed by the codebase).

- Add patches/AndroidExtensions/StdoutLogger.cpp: fix an fdsan violation
  that caused SIGABRT on Android API 29+.
  StdoutLogger::Start() calls fdopen(fd[0]) which transfers fd ownership to
  the FILE*. StdoutLogger::Stop() was then calling close(fd[0]) directly,
  violating fdsan's ownership rules. Fix: only close the write ends (fd[1])
  in Stop(); the reader threads close the read ends via fclose().

- Wire the patch into CMakeLists.txt via FetchContent_Declare PATCH_COMMAND
  so clean builds automatically apply the fix after fetching AndroidExtensions.

Test results (Android 36, arm64-v8a):
  136 JavaScript tests passing (3s)
  [  PASSED  ] 3 tests from 3 suites (JavaScript.All, Console.Log, AppRuntime.DestroyDoesNotDeadlock)
  0 failures

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
scripts/android_emulator_test.sh and scripts/hello_world/hello.c are
removed. The UnitTests Android pipeline (scripts/android_unit_tests.sh)
is the sole test entry point.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Replace 'for xml in ... 2>/dev/null' (invalid shell syntax) with
'find | while read' which handles redirection correctly.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Start adb logcat capture (after boot, before tests) into scripts/logcat.log
- Stop capture and print the path in the cleanup trap
- On failure, print filtered logcat (StdoutLogger/TestRunner/crash lines)
  inline so failures are immediately visible without extra commands
- gitignore scripts/logcat.log

Usage after a run:
  grep StdoutLogger scripts/logcat.log   # test output
  cat scripts/logcat.log                 # everything

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Initialize LOGCAT_PID to empty string before the trap is registered so
set -u does not abort if the script exits before logcat capture starts.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Replace the local PATCH_COMMAND workaround with a direct reference to
the fix commit on the fork (PR: BabylonJS/AndroidExtensions#17).
Remove patches/AndroidExtensions/StdoutLogger.cpp.

Once the PR is merged upstream, revert GIT_REPOSITORY back to
BabylonJS/AndroidExtensions and update GIT_TAG to the merge commit.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
build-android.yml:
- Add 'Install NDK' step (sdkmanager ndk;28.2.13676358) so the pinned
  NDK version is guaranteed to be present on the runner
- Add 'Build JS test bundle' step (npm install in Tests/) which triggers
  the postinstall webpack build producing UnitTests/dist/tests.js
- Add -no-snapshot -no-window -no-boot-anim -no-audio to emulator-options

ci.yml:
- Enable Android_V8 job (removes the TODO comment block)
- Keep Android_JSC commented until verified

Remove scripts/android_unit_tests.sh (superseded by the workflow).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Each line of 'script:' is executed as a separate sh -c invocation,
so cd does not persist. Use full path + -p flag instead.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ion bug

android-emulator-runner runs each script line in a separate sh -c call,
so backslash line continuations are passed as literal args to Gradle,
causing 'Task backslash not found' and -PndkVersion never reaching Gradle.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Write a proper shell script before the emulator starts:
- Clear logcat before the test run
- Capture logcat to a file in background while tests run
- Preserve the gradlew exit code
- Upload logcat.txt as a downloadable artifact per engine

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
PR BabylonJS#17 (fix-fdsan-stdout-logger) has been merged into BabylonJS/AndroidExtensions.
Switch from fork to upstream at the merge commit 5fe60c8.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
v4 runs on Node.js 20 which is deprecated on GitHub Actions runners.
v5 uses node24. All other actions in this workflow already use node24.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The Android emulator routes traffic through QEMU NAT which adds
significant latency vs native. The single-connection test already
took 1741ms of the 2000ms budget; the multi-connection test (two
serial round trips) reliably exceeded it.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
setup-java@v4 and upload-artifact@v4 tagged releases still run on
node20. Set FORCE_JAVASCRIPT_ACTIONS_TO_NODE24=true to suppress the
deprecation warning until v5 releases are available.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Re-enables Android CI coverage by bringing back emulator-based connected tests and updating supporting build/dependency plumbing so Android unit tests can run reliably in GitHub Actions.

Changes:

  • Re-enabled Android (JSC/V8) jobs in the main CI workflow.
  • Updated the Android reusable workflow to install the NDK, build the JS test bundle, and run connectedAndroidTest via the emulator runner.
  • Minor supporting updates: bump actions/checkout version, update AndroidExtensions revision, adjust a WebSocket test timeout, and fix Android NDK log header include casing.

Reviewed changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
Tests/UnitTests/Scripts/tests.ts Increases timeout for the multi-WebSocket test to reduce flakiness.
Tests/UnitTests/Android/app/src/main/cpp/JNI.cpp Fixes NDK header include casing (android/log.h).
CMakeLists.txt Updates AndroidExtensions FetchContent GIT_TAG.
.github/workflows/ci.yml Re-enables Android CI jobs (JSC and V8).
.github/workflows/build-win32.yml Bumps actions/checkout to v5.
.github/workflows/build-uwp.yml Bumps actions/checkout to v5.
.github/workflows/build-macos.yml Bumps actions/checkout to v5.
.github/workflows/build-linux.yml Bumps actions/checkout to v5.
.github/workflows/build-ios.yml Bumps actions/checkout to v5.
.github/workflows/build-android.yml Installs NDK, builds JS test bundle, and runs emulator connected tests; bumps actions/checkout to v5.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread .github/workflows/build-android.yml Outdated
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
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