diff --git a/.gitignore b/.gitignore index f70d2027d..4691f9b0e 100644 --- a/.gitignore +++ b/.gitignore @@ -35,3 +35,5 @@ test-mockup-os-release # generated dependency packages *.tar.* + +local.properties diff --git a/Build_new.md b/Build_new.md new file mode 100644 index 000000000..e36b3ecd0 --- /dev/null +++ b/Build_new.md @@ -0,0 +1,26 @@ +# Setup for J2V8 Native Library Building + +## Install Android NDK + +**Install NDK via SDK Manager** +- Open Android Studio +- Go to Tools > SDK Manager +- Click "SDK Tools" tab +- Check NDK and click apply + +**Set environment variable** +```bash +# Add to ~/.zshrc or ~/.bash_profile +export ANDROID_NDK_HOME=~/Library/Android/sdk/ndk-bundle + +# Reload shell +source ~/.zshrc +``` + +## Run the build script + +```bash +./rebuild_native.sh +``` +This will compile new .so libraries from V8 sources and place them in `src/main/jniLibs/` replacing the existing ones. +It will also run `./gradlew assembleRelease` and build the .aar artifact. \ No newline at end of file diff --git a/build.gradle b/build.gradle index 62355eff6..5be3605b2 100644 --- a/build.gradle +++ b/build.gradle @@ -12,10 +12,11 @@ ext."signing.keyId" = System.getenv("KEY_ID") buildscript { repositories { - jcenter() + google() + mavenCentral() } dependencies { - classpath 'com.android.tools.build:gradle:2.2.2' + classpath 'com.android.tools.build:gradle:8.7.3' classpath 'com.stanfy.spoon:spoon-gradle-plugin:1.2.2' } } @@ -23,30 +24,36 @@ buildscript { apply plugin: 'spoon' repositories { - jcenter() + google() + mavenCentral() } dependencies { - testCompile 'junit:junit:4.12' - //testCompile 'org.mockito:mockito-all:2.6.3' - testCompile 'org.mockito:mockito-core:2.6.3' - - androidTestCompile 'junit:junit:4.12' - androidTestCompile 'org.mockito:mockito-android:2.6.3' // https://jeroenmols.com/blog/2017/01/17/mockitoandroid/ - androidTestCompile 'com.android.support:support-annotations:24.0.0' - androidTestCompile 'com.android.support.test:runner:0.5' - androidTestCompile 'com.android.support.test:rules:0.5' + testImplementation 'junit:junit:4.13.2' + //testImplementation 'org.mockito:mockito-all:2.6.3' + testImplementation 'org.mockito:mockito-core:4.11.0' + + androidTestImplementation 'junit:junit:4.13.2' + androidTestImplementation 'org.mockito:mockito-android:4.11.0' // https://jeroenmols.com/blog/2017/01/17/mockitoandroid/ + androidTestImplementation 'androidx.annotation:annotation:1.9.1' + androidTestImplementation 'androidx.test:runner:1.6.2' + androidTestImplementation 'androidx.test:rules:1.6.1' } android { - compileSdkVersion 10 - buildToolsVersion '24.0.3' - + namespace 'com.eclipsesource.v8' + compileSdk 35 + defaultConfig { - minSdkVersion 10 - targetSdkVersion 10 + minSdkVersion 21 + targetSdkVersion 35 - testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + } + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 } lintOptions { @@ -79,10 +86,12 @@ spoon { } } -publishing { - publications { - maven(MavenPublication) { - artifact("$buildDir/outputs/aar/j2v8-release.aar") +afterEvaluate { + publishing { + publications { + maven(MavenPublication) { + artifact bundleReleaseAar + } } } -} \ No newline at end of file +} diff --git a/check_elf_alignment.sh b/check_elf_alignment.sh new file mode 100755 index 000000000..45eba7b38 --- /dev/null +++ b/check_elf_alignment.sh @@ -0,0 +1,114 @@ +#!/bin/bash +progname="${0##*/}" +progname="${progname%.sh}" + +# Usage: check_elf_alignment.sh [path to *.so files|path to *.apk] +# Copied from https://developer.android.com/guide/practices/page-sizes + +cleanup_trap() { + if [ -n "${tmp}" -a -d "${tmp}" ]; then + rm -rf ${tmp} + fi + exit $1 +} + +usage() { + echo "Host side script to check the ELF alignment of shared libraries." + echo "Shared libraries are reported ALIGNED when their ELF regions are" + echo "16 KB or 64 KB aligned. Otherwise they are reported as UNALIGNED." + echo + echo "Usage: ${progname} [input-path|input-APK|input-APEX]" +} + +if [ ${#} -ne 1 ]; then + usage + exit +fi + +case ${1} in + --help | -h | -\?) + usage + exit + ;; + + *) + dir="${1}" + ;; +esac + +if ! [ -f "${dir}" -o -d "${dir}" ]; then + echo "Invalid file: ${dir}" >&2 + exit 1 +fi + +if [[ "${dir}" == *.apk ]]; then + trap 'cleanup_trap' EXIT + + echo + echo "Recursively analyzing $dir" + echo + + if { zipalign --help 2>&1 | grep -q "\-P "; }; then + echo "=== APK zip-alignment ===" + zipalign -v -c -P 16 4 "${dir}" | egrep 'lib/arm64-v8a|lib/x86_64|Verification' + echo "=========================" + else + echo "NOTICE: Zip alignment check requires build-tools version 35.0.0-rc3 or higher." + echo " You can install the latest build-tools by running the below command" + echo " and updating your \$PATH:" + echo + echo " sdkmanager \"build-tools;35.0.0-rc3\"" + fi + + dir_filename=$(basename "${dir}") + tmp=$(mktemp -d -t "${dir_filename%.apk}_out_XXXXX") + unzip "${dir}" lib/* -d "${tmp}" >/dev/null 2>&1 + dir="${tmp}" +fi + +if [[ "${dir}" == *.apex ]]; then + trap 'cleanup_trap' EXIT + + echo + echo "Recursively analyzing $dir" + echo + + dir_filename=$(basename "${dir}") + tmp=$(mktemp -d -t "${dir_filename%.apex}_out_XXXXX") + deapexer extract "${dir}" "${tmp}" || { echo "Failed to deapex." && exit 1; } + dir="${tmp}" +fi + +RED="\e[31m" +GREEN="\e[32m" +ENDCOLOR="\e[0m" + +unaligned_libs=() + +echo +echo "=== ELF alignment ===" + +matches="$(find "${dir}" -type f)" +IFS=$'\n' +for match in $matches; do + # We could recursively call this script or rewrite it to though. + [[ "${match}" == *".apk" ]] && echo "WARNING: doesn't recursively inspect .apk file: ${match}" + [[ "${match}" == *".apex" ]] && echo "WARNING: doesn't recursively inspect .apex file: ${match}" + + [[ $(file "${match}") == *"ELF"* ]] || continue + + res="$(objdump -p "${match}" | grep LOAD | awk '{ print $NF }' | head -1)" + if [[ $res =~ 2\*\*(1[4-9]|[2-9][0-9]|[1-9][0-9]{2,}) ]]; then + echo -e "${match}: ${GREEN}ALIGNED${ENDCOLOR} ($res)" + else + echo -e "${match}: ${RED}UNALIGNED${ENDCOLOR} ($res)" + unaligned_libs+=("${match}") + fi +done + +if [ ${#unaligned_libs[@]} -gt 0 ]; then + echo -e "${RED}Found ${#unaligned_libs[@]} unaligned libs (only arm64-v8a/x86_64 libs need to be aligned).${ENDCOLOR}" +elif [ -n "${dir_filename}" ]; then + echo -e "ELF Verification Successful" +fi +echo "=====================" diff --git a/gradle.properties b/gradle.properties index 85eb5dfb5..97cf8b490 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,3 +1,4 @@ #increase jvm heap space available for gradle #(allows to run dex in the same process as gradle) org.gradle.jvmargs=-Xmx4608M +android.useAndroidX=true diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index d9f66cd9b..8ce71da2f 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Mon Dec 15 11:54:06 CET 2014 -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip +#Thu Jun 05 09:06:59 CEST 2025 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/jni/com_eclipsesource_v8_V8Impl.cpp b/jni/com_eclipsesource_v8_V8Impl.cpp index 58e748bbe..013b72fad 100644 --- a/jni/com_eclipsesource_v8_V8Impl.cpp +++ b/jni/com_eclipsesource_v8_V8Impl.cpp @@ -21,11 +21,13 @@ #define TAG "J2V8_V8Impl" +#ifdef _WIN32 #pragma comment(lib, "userenv.lib") #pragma comment(lib, "IPHLPAPI.lib") #pragma comment(lib, "Ws2_32.lib") #pragma comment(lib, "WINMM.lib") #pragma comment( lib, "psapi.lib" ) +#endif using namespace std; using namespace v8; diff --git a/rebuild_native.sh b/rebuild_native.sh new file mode 100755 index 000000000..d70c4c168 --- /dev/null +++ b/rebuild_native.sh @@ -0,0 +1,127 @@ +#!/bin/bash + +# A script to rebuild J2V8 native libraries for Android + +set -e + +echo "J2V8 Native Library Rebuild Script" +echo "==================================" +echo "✅ Builds 16KB-aligned .so libraries for Google Play compliance" + +# Check if Android NDK is available +if [ -z "$ANDROID_NDK_HOME" ]; then + echo "ERROR: ANDROID_NDK_HOME environment variable not set" + echo "Please install Android NDK and set ANDROID_NDK_HOME" + exit 1 +fi + +# Create output directories (replace existing libraries in src/main/jniLibs) +mkdir -p src/main/jniLibs/arm64-v8a +mkdir -p src/main/jniLibs/armeabi-v7a +mkdir -p src/main/jniLibs/x86 +mkdir -p src/main/jniLibs/x86_64 +mkdir -p build_native/android + +if [ -d "v8.out" ]; then + echo "✅ V8 libraries found:" + find v8.out -name "*.a" | sort +else + # Taken from https://download.eclipsesource.com/j2v8/v8/libv8_9.3.345.11_monolith.zip + # Added to VCS in case the link breaks + unzip v8_monolith/libv8_9.3.345.11_monolith.zip -d v8.out +fi + +API_LEVEL=21 + +# Function to build for a specific architecture +build_arch() { + local android_abi=$1 + local v8_arch=$2 + local ndk_arch=$3 + + echo "" + echo "Building for $android_abi ($v8_arch)..." + + # Set up compiler paths + local TOOLCHAIN="$ANDROID_NDK_HOME/toolchains/llvm/prebuilt/darwin-x86_64" + if [ ! -d "$TOOLCHAIN" ]; then + # Try linux toolchain + TOOLCHAIN="$ANDROID_NDK_HOME/toolchains/llvm/prebuilt/linux-x86_64" + fi + + if [ ! -d "$TOOLCHAIN" ]; then + echo "ERROR: Could not find Android NDK toolchain" + return 1 + fi + + local CC="$TOOLCHAIN/bin/${ndk_arch}${API_LEVEL}-clang" + local CXX="$TOOLCHAIN/bin/${ndk_arch}${API_LEVEL}-clang++" + + if [ ! -f "$CC" ]; then + echo "ERROR: Compiler not found: $CC" + return 1 + fi + + echo "Using compiler: $CC" + + # Generate JNI header if needed + if [ ! -f "jni/com_eclipsesource_v8_V8Impl.h" ]; then + echo "Generating JNI headers..." + if [ -d "build/intermediates/javac/release/classes" ]; then + javah -cp build/intermediates/javac/release/classes -o jni com.eclipsesource.v8.V8Impl || echo "Warning: Could not generate JNI headers" + else + echo "Warning: Java classes not found, using existing JNI headers" + fi + fi + + # Compile flags with release optimizations + local CPPFLAGS="-I$ANDROID_NDK_HOME/sysroot/usr/include" + CPPFLAGS="$CPPFLAGS -I$ANDROID_NDK_HOME/sysroot/usr/include/$ndk_arch" + CPPFLAGS="$CPPFLAGS -Iv8.out/include" + CPPFLAGS="$CPPFLAGS -Ijni" + CPPFLAGS="$CPPFLAGS -fPIC -std=c++17 -O3 -DNDEBUG" + + # Link flags with 16KB alignment for Google Play compliance and symbol stripping + local LDFLAGS="-shared -llog -s" + LDFLAGS="$LDFLAGS -Wl,-z,max-page-size=16384" + LDFLAGS="$LDFLAGS -Wl,-z,common-page-size=16384" + + # Output directly to src/main/jniLibs (replace existing files under version control) + local OUTPUT="src/main/jniLibs/$android_abi/libj2v8.so" + + echo "Compiling libj2v8 for $android_abi..." + + # Compile the JNI implementation + if ! $CXX $CPPFLAGS -c jni/com_eclipsesource_v8_V8Impl.cpp -o "build_native/android/v8impl_$android_abi.o"; then + echo "ERROR: Compilation failed for $android_abi" + return 1 + fi + + echo "Linking libj2v8 for $android_abi..." + + # Link with V8 and output directly to jniLibs + if ! $CXX $LDFLAGS -o "$OUTPUT" "build_native/android/v8impl_$android_abi.o" "$v8_lib"; then + echo "ERROR: Linking failed for $android_abi" + return 1 + fi + + echo "✅ Built: $OUTPUT" + ls -lh "$OUTPUT" +} + +# Build for each architecture +echo "Building for all Android architectures..." + +build_arch "arm64-v8a" "android.arm64" "aarch64-linux-android" +build_arch "armeabi-v7a" "android.arm" "armv7a-linux-androideabi" +build_arch "x86" "android.x86" "i686-linux-android" +build_arch "x86_64" "android.x64" "x86_64-linux-android" + +echo "" +echo "Native library rebuild complete!" +echo "Libraries compiled and replaced in src/main/jniLibs:" +ls -la src/main/jniLibs/*/libj2v8.so 2>/dev/null || echo "No libraries found in src/main/jniLibs/" +echo "" +./check_elf_alignment.sh src/main/jniLibs +echo "Running './gradlew assembleRelease' to build the AAR with the new native libraries" +./gradlew assembleRelease diff --git a/src/main/jniLibs/arm64-v8a/libj2v8.so b/src/main/jniLibs/arm64-v8a/libj2v8.so old mode 100644 new mode 100755 index 6ca367ce5..d7035897e Binary files a/src/main/jniLibs/arm64-v8a/libj2v8.so and b/src/main/jniLibs/arm64-v8a/libj2v8.so differ diff --git a/src/main/jniLibs/armeabi-v7a/libj2v8.so b/src/main/jniLibs/armeabi-v7a/libj2v8.so old mode 100644 new mode 100755 index 0da77a1b5..f4e51fe43 Binary files a/src/main/jniLibs/armeabi-v7a/libj2v8.so and b/src/main/jniLibs/armeabi-v7a/libj2v8.so differ diff --git a/src/main/jniLibs/x86/libj2v8.so b/src/main/jniLibs/x86/libj2v8.so old mode 100644 new mode 100755 index 70b3bc5e0..e3a328ae2 Binary files a/src/main/jniLibs/x86/libj2v8.so and b/src/main/jniLibs/x86/libj2v8.so differ diff --git a/src/main/jniLibs/x86_64/libj2v8.so b/src/main/jniLibs/x86_64/libj2v8.so old mode 100644 new mode 100755 index 1581acc4f..6c85e5917 Binary files a/src/main/jniLibs/x86_64/libj2v8.so and b/src/main/jniLibs/x86_64/libj2v8.so differ diff --git a/v8_monolith/libv8_9.3.345.11_monolith.zip b/v8_monolith/libv8_9.3.345.11_monolith.zip new file mode 100644 index 000000000..ee0fdf5f4 Binary files /dev/null and b/v8_monolith/libv8_9.3.345.11_monolith.zip differ