From 625af30b82a4e31ee7e8ca1f61c69deed069eff7 Mon Sep 17 00:00:00 2001 From: Matt Hargett Date: Thu, 4 Jun 2026 12:01:26 -0700 Subject: [PATCH 1/3] Port remaining Android XR compatibility fixes --- .github/workflows/build-android.yml | 2 +- .../V8Inspector/Source/V8InspectorAgent.cpp | 20 +++++++--- Core/Node-API/package-jsc.json | 2 +- README.md | 6 +-- Tests/UnitTests/Android/app/build.gradle | 39 ++++++++++++++----- .../Android/app/src/main/cpp/JNI.cpp | 2 +- 6 files changed, 50 insertions(+), 21 deletions(-) diff --git a/.github/workflows/build-android.yml b/.github/workflows/build-android.yml index 97b1690d..ba559092 100644 --- a/.github/workflows/build-android.yml +++ b/.github/workflows/build-android.yml @@ -38,7 +38,7 @@ jobs: - name: Run Connected Android Test uses: reactivecircus/android-emulator-runner@v2 with: - api-level: 33 + api-level: 35 target: google_apis arch: x86_64 emulator-options: -no-snapshot -no-window -no-boot-anim -no-audio diff --git a/Core/AppRuntime/V8Inspector/Source/V8InspectorAgent.cpp b/Core/AppRuntime/V8Inspector/Source/V8InspectorAgent.cpp index 2f1f1f5f..747d0b9b 100644 --- a/Core/AppRuntime/V8Inspector/Source/V8InspectorAgent.cpp +++ b/Core/AppRuntime/V8Inspector/Source/V8InspectorAgent.cpp @@ -7,6 +7,9 @@ #include #include +#if __has_include() +#include +#endif #include #include @@ -194,7 +197,14 @@ namespace Babylon void ConnectFrontend() { - session_ = inspector_->connect(1, new ChannelImpl(agent_), v8_inspector::StringView(), v8_inspector::V8Inspector::kFullyTrusted); +#if defined(V8_MAJOR_VERSION) && (V8_MAJOR_VERSION >= 11) + session_ = inspector_->connect( + 1, new ChannelImpl(agent_), v8_inspector::StringView(), + v8_inspector::V8Inspector::kFullyTrusted); +#else + session_ = inspector_->connect( + 1, new ChannelImpl(agent_), v8_inspector::StringView()); +#endif } void DisconnectFrontend() @@ -419,9 +429,9 @@ namespace Babylon } v8::Local string_value = v8::Local::Cast(value); int len = string_value->Length(); - std::basic_string buffer(len, '\0'); - string_value->Write(v8::Isolate::GetCurrent(), reinterpret_cast(&buffer[0]), 0, len); // Write expects uint16_t* but the template parameter is char16_t - return v8_inspector::StringBuffer::create(v8_inspector::StringView(reinterpret_cast(buffer.data()), len)); + std::vector buffer(len); + string_value->Write(v8::Isolate::GetCurrent(), buffer.data(), 0, len); + return v8_inspector::StringBuffer::create(v8_inspector::StringView(buffer.data(), len)); } bool AgentImpl::AppendMessage( @@ -661,4 +671,4 @@ namespace Babylon return "file://" + script_path_; } -} // namespace inspector \ No newline at end of file +} // namespace inspector diff --git a/Core/Node-API/package-jsc.json b/Core/Node-API/package-jsc.json index d9f70a7a..70703a85 100644 --- a/Core/Node-API/package-jsc.json +++ b/Core/Node-API/package-jsc.json @@ -1,5 +1,5 @@ { "dependencies": { - "jsc-android": "250231.0.0" + "jsc-android": "294992.0.0" } } diff --git a/README.md b/README.md index cbe25f0f..3522fa58 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,7 @@ npm install _Follow the steps from [All Development Platforms](#all-development-platforms) before proceeding._ **Required Tools:** -[Android Studio](https://developer.android.com/studio), [Node.js](https://nodejs.org/en/download/), [Ninja](https://ninja-build.org/) +[Android Studio](https://developer.android.com/studio) with Android NDK 28.2.13676358 and API level 35 SDK platform installed, [Node.js](https://nodejs.org/en/download/), [Ninja](https://ninja-build.org/) The minimal requirement target is Android 5.0. @@ -42,7 +42,7 @@ An `.apk` that can be executed on your device or simulator is the output. First, download the latest release of Ninja, extract the binary, and add it to your system path. -Once you have Android Studio downloaded, you need to set up an Android emulator if you do not have a physical Android device. You can do this by selecting `Tools` -> `Device Manager` and then selecting a device. (We are using Pixel 2 API 27). +Once you have Android Studio downloaded, you need to set up an Android emulator if you do not have a physical Android device. You can do this by selecting `Tools` -> `Device Manager` and then selecting a device. (We are using Pixel 2 API 35). Open the project located at `JsRuntimeHost\Tests\UnitTests\Android` with Android Studio. Note that this can take a while to load. (The bottom right corner of the Android Studio window shows you what is currently being loaded.) @@ -68,4 +68,4 @@ Security Response Center (MSRC) at [secure@microsoft.com](mailto:secure@microsof You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Further information, including the [MSRC PGP](https://technet.microsoft.com/en-us/security/dn606155) key, can -be found in the [Security TechCenter](https://technet.microsoft.com/en-us/security/default). \ No newline at end of file +be found in the [Security TechCenter](https://technet.microsoft.com/en-us/security/default). diff --git a/Tests/UnitTests/Android/app/build.gradle b/Tests/UnitTests/Android/app/build.gradle index fc8f7d70..bf12880d 100644 --- a/Tests/UnitTests/Android/app/build.gradle +++ b/Tests/UnitTests/Android/app/build.gradle @@ -7,18 +7,18 @@ if (project.hasProperty("jsEngine")) { jsEngine = project.property("jsEngine") } +def targetApiLevel = 35 +def requiredNdkVersion = project.findProperty("ndkVersion") ?: "28.2.13676358" + android { namespace 'com.jsruntimehost.unittests' - compileSdk 33 - ndkVersion = "23.1.7779620" - if (project.hasProperty("ndkVersion")) { - ndkVersion = project.property("ndkVersion") - } + compileSdk targetApiLevel + ndkVersion = requiredNdkVersion defaultConfig { applicationId "com.jsruntimehost.unittests" minSdk 21 - targetSdk 33 + targetSdk targetApiLevel versionCode 1 versionName "1.0" @@ -26,7 +26,7 @@ android { externalNativeBuild { cmake { - arguments ( + arguments( "-DANDROID_STL=c++_shared", "-DNAPI_JAVASCRIPT_ENGINE=${jsEngine}", "-DJSRUNTIMEHOST_CORE_APPRUNTIME_V8_INSPECTOR=ON" @@ -34,9 +34,28 @@ android { } } - if (project.hasProperty("abiFilters")) { - ndk { - abiFilters project.getProperty("abiFilters") + ndk { + def abiFiltersProp = project.findProperty("abiFilters")?.toString() + if (abiFiltersProp) { + def propFilters = abiFiltersProp.split(',').collect { it.trim() }.findAll { !it.isEmpty() } + if (!propFilters.isEmpty()) { + abiFilters(*propFilters) + } + } else { + def requestedAbi = project.findProperty("android.injected.build.abi") ?: System.getenv("ANDROID_ABI") + def defaultAbis = [] + if (requestedAbi) { + defaultAbis = requestedAbi.split(',').collect { it.trim() }.findAll { !it.isEmpty() } + } + if (defaultAbis.isEmpty()) { + def hostArch = (System.getProperty("os.arch") ?: "").toLowerCase() + if (hostArch.contains("aarch64") || hostArch.contains("arm64")) { + defaultAbis = ['arm64-v8a'] + } else { + defaultAbis = ['arm64-v8a', 'x86_64'] + } + } + abiFilters(*defaultAbis) } } } diff --git a/Tests/UnitTests/Android/app/src/main/cpp/JNI.cpp b/Tests/UnitTests/Android/app/src/main/cpp/JNI.cpp index 4415ce87..978dd66d 100644 --- a/Tests/UnitTests/Android/app/src/main/cpp/JNI.cpp +++ b/Tests/UnitTests/Android/app/src/main/cpp/JNI.cpp @@ -22,7 +22,7 @@ Java_com_jsruntimehost_unittests_Native_javaScriptTests(JNIEnv* env, jclass claz android::global::Initialize(javaVM, context); Babylon::DebugTrace::EnableDebugTrace(true); - Babylon::DebugTrace::SetTraceOutput([](const char* trace) { printf("%s\n", trace); fflush(stdout); }); + Babylon::DebugTrace::SetTraceOutput([](const char* trace) { __android_log_print(ANDROID_LOG_INFO, "JsRuntimeHost", "%s", trace); }); auto testResult = RunTests(); From 024219eac965950714960da9b5c6d871a53b1587 Mon Sep 17 00:00:00 2001 From: Matt Hargett Date: Fri, 5 Jun 2026 00:05:01 -0700 Subject: [PATCH 2/3] V8Inspector: guard __has_include for portability (review) Wrap the v8-version.h probe in `#if defined(__has_include)` so it's safe even on a preprocessor that doesn't provide __has_include (standard in C++17+, which this project uses, but the guarded form is the conventional portable idiom). When __has_include is unavailable, V8_MAJOR_VERSION stays undefined and ConnectFrontend() falls back to the 3-arg connect(). --- Core/AppRuntime/V8Inspector/Source/V8InspectorAgent.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/AppRuntime/V8Inspector/Source/V8InspectorAgent.cpp b/Core/AppRuntime/V8Inspector/Source/V8InspectorAgent.cpp index 747d0b9b..6835b162 100644 --- a/Core/AppRuntime/V8Inspector/Source/V8InspectorAgent.cpp +++ b/Core/AppRuntime/V8Inspector/Source/V8InspectorAgent.cpp @@ -7,7 +7,7 @@ #include #include -#if __has_include() +#if defined(__has_include) && __has_include() #include #endif From 24a18745cc1f8837a641895ebadf5800e6345930 Mon Sep 17 00:00:00 2001 From: Matt Hargett Date: Fri, 5 Jun 2026 00:33:35 -0700 Subject: [PATCH 3/3] JNI: comment why debug-trace logs direct to logcat (distinct adb tag) Document that the DebugTrace callback uses __android_log_print with a dedicated "JsRuntimeHost" tag rather than routing through AndroidExtensions StdoutLogger -- so connected-test diagnostics are filterable via `adb logcat -s JsRuntimeHost` instead of interleaving with all stdout under one tag. --- Tests/UnitTests/Android/app/src/main/cpp/JNI.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Tests/UnitTests/Android/app/src/main/cpp/JNI.cpp b/Tests/UnitTests/Android/app/src/main/cpp/JNI.cpp index 978dd66d..25818844 100644 --- a/Tests/UnitTests/Android/app/src/main/cpp/JNI.cpp +++ b/Tests/UnitTests/Android/app/src/main/cpp/JNI.cpp @@ -22,6 +22,10 @@ Java_com_jsruntimehost_unittests_Native_javaScriptTests(JNIEnv* env, jclass claz android::global::Initialize(javaVM, context); Babylon::DebugTrace::EnableDebugTrace(true); + // Emit debug-trace lines straight to logcat under a dedicated "JsRuntimeHost" tag instead of + // routing them through AndroidExtensions' StdoutLogger (which forwards all stdout under a single + // tag, interleaved with the gtest output). The distinct tag keeps connected-test diagnostics + // filterable, e.g. `adb logcat -s JsRuntimeHost`. Babylon::DebugTrace::SetTraceOutput([](const char* trace) { __android_log_print(ANDROID_LOG_INFO, "JsRuntimeHost", "%s", trace); }); auto testResult = RunTests();