From ebec68af99adfc57ced8e183706ac2b06f66db85 Mon Sep 17 00:00:00 2001
From: zocomputer <zandy@failure.fail>
Date: Sun, 27 Sep 2026 01:04:44 +0000
Subject: [PATCH] Build JRE 27 (jdk-27-ga) for Android aarch64

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---
 5_clonejdk.sh                              |    2 +
 6_buildjdk.sh                              |    2 +-
 7_removejdkdebuginfo.sh                    |   10 +-
 awt_xawt_stub/awt_xawt_stub.c              |   37 +
 patches/jre_27/android/jdk27u_android.diff | 2410 ++++++++++++++++++++
 5 files changed, 2458 insertions(+), 3 deletions(-)
 create mode 100644 awt_xawt_stub/awt_xawt_stub.c
 create mode 100644 patches/jre_27/android/jdk27u_android.diff

diff --git a/5_clonejdk.sh b/5_clonejdk.sh
index eec7d55..e9c19b6 100755
--- a/5_clonejdk.sh
+++ b/5_clonejdk.sh
@@ -8,6 +8,8 @@ if [[ $TARGET_VERSION -eq 21 ]]; then
         # TODO: Update Android to JDK 21.0.8+7
         git clone --branch jdk21.0.1 --depth 1 https://github.com/openjdk/jdk21u openjdk-21
     fi
+elif [[ $TARGET_VERSION -eq 27 ]]; then
+    [ -d openjdk-27 ] || git clone --branch jdk-27-ga --depth 1 https://github.com/openjdk/jdk27u openjdk-27
 elif [[ $TARGET_VERSION -eq 25 ]]; then
     git clone --branch jdk-25.0.1+8 --depth 1 https://github.com/openjdk/jdk25u openjdk-25
 else
diff --git a/6_buildjdk.sh b/6_buildjdk.sh
index b2fdbad..9ef6d24 100755
--- a/6_buildjdk.sh
+++ b/6_buildjdk.sh
@@ -138,7 +138,7 @@ jobs=4
 if [[ "$BUILD_IOS" == "1" ]]; then
   jobs=$(sysctl -n hw.ncpu)
 else
-  jobs=$(nproc)
+  jobs=${JOBS_OVERRIDE:-$(nproc)}
 fi
 
 # Failsafe environment variable for computers with too many cores
diff --git a/7_removejdkdebuginfo.sh b/7_removejdkdebuginfo.sh
index 5508bfc..169db0a 100755
--- a/7_removejdkdebuginfo.sh
+++ b/7_removejdkdebuginfo.sh
@@ -22,7 +22,7 @@ cp -r $imagespath/jdk jdkout
 
 export EXTRA_JLINK_OPTION=
 
-if [[ "$TARGET_JDK" == "aarch64" ]] || [[ "$TARGET_JDK" == "x86_64" ]]; then
+if [[ $TARGET_VERSION -lt 27 ]] && ( [[ "$TARGET_JDK" == "aarch64" ]] || [[ "$TARGET_JDK" == "x86_64" ]] ); then
    echo "Building for aarch64 or x86_64, introducing JVMCI module"
    export EXTRA_JLINK_OPTION=,jdk.internal.vm.ci
 fi
@@ -34,9 +34,15 @@ else
    export JLINK_STRIP_ARG="--strip-debug"
 fi
 
+JLINK_MODULES=java.base,java.compiler,java.datatransfer,java.desktop,java.instrument,java.logging,java.management,java.management.rmi,java.naming,java.net.http,java.prefs,java.rmi,java.scripting,java.se,java.security.jgss,java.security.sasl,java.sql,java.sql.rowset,java.transaction.xa,java.xml,java.xml.crypto,jdk.accessibility,jdk.charsets,jdk.crypto.cryptoki,jdk.crypto.ec,jdk.dynalink,jdk.httpserver,jdk.jdwp.agent,jdk.jfr,jdk.jsobject,jdk.localedata,jdk.management,jdk.management.agent,jdk.management.jfr,jdk.naming.dns,jdk.naming.rmi,jdk.net,jdk.nio.mapmode,jdk.sctp,jdk.security.auth,jdk.security.jgss,jdk.unsupported,jdk.xml.dom,jdk.zipfs$EXTRA_JLINK_OPTION
+if [[ $TARGET_VERSION -ge 27 ]]; then
+   # Same module set as the AngelAuraMC jre25 release (jdk.jsobject and JVMCI no longer exist in 27)
+   JLINK_MODULES=java.base,java.compiler,java.datatransfer,java.xml,java.prefs,java.desktop,java.instrument,java.logging,java.management,java.security.sasl,java.naming,java.rmi,java.management.rmi,java.net.http,java.scripting,java.security.jgss,java.transaction.xa,java.sql,java.sql.rowset,java.xml.crypto,java.se,jdk.accessibility,jdk.charsets,jdk.internal.opt,jdk.zipfs,jdk.compiler,jdk.crypto.cryptoki,jdk.crypto.ec,jdk.dynalink,jdk.internal.ed,jdk.editpad,jdk.hotspot.agent,jdk.httpserver,jdk.incubator.vector,jdk.internal.jvmstat,jdk.internal.le,jdk.internal.md,jdk.jdwp.agent,jdk.jfr,jdk.localedata,jdk.management,jdk.management.agent,jdk.management.jfr,jdk.naming.dns,jdk.naming.rmi,jdk.net,jdk.nio.mapmode,jdk.sctp,jdk.security.auth,jdk.security.jgss,jdk.unsupported,jdk.xml.dom
+fi
+
 jlink \
 --module-path=jdkout/jmods \
---add-modules java.base,java.compiler,java.datatransfer,java.desktop,java.instrument,java.logging,java.management,java.management.rmi,java.naming,java.net.http,java.prefs,java.rmi,java.scripting,java.se,java.security.jgss,java.security.sasl,java.sql,java.sql.rowset,java.transaction.xa,java.xml,java.xml.crypto,jdk.accessibility,jdk.charsets,jdk.crypto.cryptoki,jdk.crypto.ec,jdk.dynalink,jdk.httpserver,jdk.jdwp.agent,jdk.jfr,jdk.jsobject,jdk.localedata,jdk.management,jdk.management.agent,jdk.management.jfr,jdk.naming.dns,jdk.naming.rmi,jdk.net,jdk.nio.mapmode,jdk.sctp,jdk.security.auth,jdk.security.jgss,jdk.unsupported,jdk.xml.dom,jdk.zipfs$EXTRA_JLINK_OPTION \
+--add-modules $JLINK_MODULES \
 --output jreout \
 $JLINK_STRIP_ARG \
 --no-man-pages \
diff --git a/awt_xawt_stub/awt_xawt_stub.c b/awt_xawt_stub/awt_xawt_stub.c
new file mode 100644
index 0000000..32747d4
--- /dev/null
+++ b/awt_xawt_stub/awt_xawt_stub.c
@@ -0,0 +1,37 @@
+/* Stub libawt_xawt.so for Android (no X11). Mirrors the stub shipped in AngelAuraMC/FCL jre25:
+ * every symbol is a no-op returning 0, and the library depends on libawt_headless.so. */
+#include <jni.h>
+JNIEXPORT jlong JNICALL Java_java_awt_AWTEvent_initIDs(JNIEnv *env, jobject obj) { return 0; }
+JNIEXPORT jlong JNICALL Java_java_awt_AWTEvent_nativeSetSource(JNIEnv *env, jobject obj) { return 0; }
+JNIEXPORT jlong JNICALL Java_java_awt_Button_initIDs(JNIEnv *env, jobject obj) { return 0; }
+JNIEXPORT jlong JNICALL Java_java_awt_Checkbox_initIDs(JNIEnv *env, jobject obj) { return 0; }
+JNIEXPORT jlong JNICALL Java_java_awt_Component_initIDs(JNIEnv *env, jobject obj) { return 0; }
+JNIEXPORT jlong JNICALL Java_java_awt_Container_initIDs(JNIEnv *env, jobject obj) { return 0; }
+JNIEXPORT jlong JNICALL Java_java_awt_Cursor_finalizeImpl(JNIEnv *env, jobject obj) { return 0; }
+JNIEXPORT jlong JNICALL Java_java_awt_Cursor_initIDs(JNIEnv *env, jobject obj) { return 0; }
+JNIEXPORT jlong JNICALL Java_java_awt_Dialog_initIDs(JNIEnv *env, jobject obj) { return 0; }
+JNIEXPORT jlong JNICALL Java_java_awt_Event_initIDs(JNIEnv *env, jobject obj) { return 0; }
+JNIEXPORT jlong JNICALL Java_java_awt_FileDialog_initIDs(JNIEnv *env, jobject obj) { return 0; }
+JNIEXPORT jlong JNICALL Java_java_awt_Frame_initIDs(JNIEnv *env, jobject obj) { return 0; }
+JNIEXPORT jlong JNICALL Java_java_awt_Insets_initIDs(JNIEnv *env, jobject obj) { return 0; }
+JNIEXPORT jlong JNICALL Java_java_awt_KeyboardFocusManager_initIDs(JNIEnv *env, jobject obj) { return 0; }
+JNIEXPORT jlong JNICALL Java_java_awt_MenuComponent_initIDs(JNIEnv *env, jobject obj) { return 0; }
+JNIEXPORT jlong JNICALL Java_java_awt_MenuItem_initIDs(JNIEnv *env, jobject obj) { return 0; }
+JNIEXPORT jlong JNICALL Java_java_awt_Menu_initIDs(JNIEnv *env, jobject obj) { return 0; }
+JNIEXPORT jlong JNICALL Java_java_awt_ScrollPane_initIDs(JNIEnv *env, jobject obj) { return 0; }
+JNIEXPORT jlong JNICALL Java_java_awt_Scrollbar_initIDs(JNIEnv *env, jobject obj) { return 0; }
+JNIEXPORT jlong JNICALL Java_java_awt_TextArea_initIDs(JNIEnv *env, jobject obj) { return 0; }
+JNIEXPORT jlong JNICALL Java_java_awt_TextField_initIDs(JNIEnv *env, jobject obj) { return 0; }
+JNIEXPORT jlong JNICALL Java_java_awt_TrayIcon_initIDs(JNIEnv *env, jobject obj) { return 0; }
+JNIEXPORT jlong JNICALL Java_java_awt_Window_initIDs(JNIEnv *env, jobject obj) { return 0; }
+JNIEXPORT jlong JNICALL Java_java_awt_event_InputEvent_initIDs(JNIEnv *env, jobject obj) { return 0; }
+JNIEXPORT jlong JNICALL Java_java_awt_event_KeyEvent_initIDs(JNIEnv *env, jobject obj) { return 0; }
+JNIEXPORT jlong JNICALL Java_sun_awt_SunToolkit_closeSplashScreen(JNIEnv *env, jobject obj) { return 0; }
+JNIEXPORT jlong JNICALL Java_sun_awt_UNIXToolkit_check_1gtk(JNIEnv *env, jobject obj) { return 0; }
+JNIEXPORT jlong JNICALL Java_sun_awt_UNIXToolkit_get_1gtk_1version(JNIEnv *env, jobject obj) { return 0; }
+JNIEXPORT jlong JNICALL Java_sun_awt_UNIXToolkit_gtkCheckVersionImpl(JNIEnv *env, jobject obj) { return 0; }
+JNIEXPORT jlong JNICALL Java_sun_awt_UNIXToolkit_load_1gtk(JNIEnv *env, jobject obj) { return 0; }
+JNIEXPORT jlong JNICALL Java_sun_awt_UNIXToolkit_load_1gtk_1icon(JNIEnv *env, jobject obj) { return 0; }
+JNIEXPORT jlong JNICALL Java_sun_awt_UNIXToolkit_load_1stock_1icon(JNIEnv *env, jobject obj) { return 0; }
+JNIEXPORT jlong JNICALL Java_sun_awt_UNIXToolkit_nativeSync(JNIEnv *env, jobject obj) { return 0; }
+JNIEXPORT jlong JNICALL Java_sun_awt_UNIXToolkit_unload_1gtk(JNIEnv *env, jobject obj) { return 0; }
diff --git a/patches/jre_27/android/jdk27u_android.diff b/patches/jre_27/android/jdk27u_android.diff
new file mode 100644
index 0000000..2a55a46
--- /dev/null
+++ b/patches/jre_27/android/jdk27u_android.diff
@@ -0,0 +1,2410 @@
+diff --git a/configure b/configure
+index 78d305642..a50a36fde 100644
+--- a/configure
++++ b/configure
+@@ -28,10 +28,6 @@
+ # Get an absolute path to this script, since that determines the top-level directory.
+ source_path="$(dirname ${0})"
+ this_script_dir="$(cd -- "${source_path}" > /dev/null && pwd)"
+-if test -z "${this_script_dir}"; then
+-  echo "Error: Could not determine location of configure script"
+-  exit 1
+-fi
+ 
+ # Delegate to wrapper, forcing wrapper to believe $0 is this script by using -c.
+ # This trick is needed to get autoconf to co-operate properly.
+diff --git a/make/autoconf/flags-cflags.m4 b/make/autoconf/flags-cflags.m4
+index 423654cd5..c9643b872 100644
+--- a/make/autoconf/flags-cflags.m4
++++ b/make/autoconf/flags-cflags.m4
+@@ -790,11 +790,11 @@ AC_DEFUN([FLAGS_SETUP_CFLAGS_CPU_DEP],
+     fi
+   fi
+ 
+-  if test "x$TOOLCHAIN_TYPE" = xgcc; then
++  #if test "x$TOOLCHAIN_TYPE" = xgcc; then
+     # This flag is required since GCC 6 as undefined behavior in OpenJDK code
+     # runs afoul of the more aggressive versions of this optimization.
+-    $1_TOOLCHAIN_CFLAGS="-fno-lifetime-dse"
+-  fi
++  #  $1_TOOLCHAIN_CFLAGS="-fno-lifetime-dse"
++  #fi
+ 
+   if test "x$TOOLCHAIN_TYPE" = xmicrosoft; then
+     REPRODUCIBLE_CFLAGS="-experimental:deterministic"
+diff --git a/make/autoconf/flags-ldflags.m4 b/make/autoconf/flags-ldflags.m4
+index ff1082873..c01052ea1 100644
+--- a/make/autoconf/flags-ldflags.m4
++++ b/make/autoconf/flags-ldflags.m4
+@@ -188,7 +188,9 @@ AC_DEFUN([FLAGS_SETUP_LDFLAGS_CPU_DEP],
+         test "x${OPENJDK_$1_CPU}" = xmips64el; then
+       $1_CPU_LDFLAGS="${$1_CPU_LDFLAGS} -Wl,--hash-style=sysv"
+     else
+-      $1_CPU_LDFLAGS="${$1_CPU_LDFLAGS} -Wl,--hash-style=gnu"
++      # Android 5.x does not support GNU hash style
++      # gnu
++      $1_CPU_LDFLAGS="${$1_CPU_LDFLAGS} -Wl,--hash-style=sysv"
+     fi
+ 
+   elif test "x$TOOLCHAIN_TYPE" = xmicrosoft; then
+diff --git a/make/autoconf/lib-freetype.m4 b/make/autoconf/lib-freetype.m4
+index 8d524c8c8..5399a8bd7 100644
+--- a/make/autoconf/lib-freetype.m4
++++ b/make/autoconf/lib-freetype.m4
+@@ -105,7 +105,8 @@ AC_DEFUN_ONCE([LIB_SETUP_FREETYPE],
+   FREETYPE_TO_USE=bundled
+   if test "x$OPENJDK_TARGET_OS" != "xwindows" && \
+       test "x$OPENJDK_TARGET_OS" != "xmacosx" && \
+-      test "x$OPENJDK_TARGET_OS" != "xaix"; then
++      test "x$OPENJDK_TARGET_OS" != "xaix" && \
++      test "x$OPENJDK_TARGET_OS" != "xandroid"; then
+     FREETYPE_TO_USE=system
+   fi
+   if test "x$with_freetype" != "x" ; then
+diff --git a/make/autoconf/libraries.m4 b/make/autoconf/libraries.m4
+index 5daacdc1c..78c51da67 100644
+--- a/make/autoconf/libraries.m4
++++ b/make/autoconf/libraries.m4
+@@ -44,6 +44,7 @@ AC_DEFUN_ONCE([LIB_DETERMINE_DEPENDENCIES],
+   # Check if X11 is needed
+   if test "x$OPENJDK_TARGET_OS" = xwindows ||
+      test "x$OPENJDK_TARGET_OS" = xmacosx ||
++     test "x$OPENJDK_TARGET_OS" = xandroid ||
+      test "x$ENABLE_HEADLESS_ONLY" = xtrue; then
+     NEEDS_LIB_X11=false
+   else
+@@ -52,8 +53,8 @@ AC_DEFUN_ONCE([LIB_DETERMINE_DEPENDENCIES],
+   fi
+ 
+   # Check if fontconfig is needed
+-  if test "x$OPENJDK_TARGET_OS" = xwindows || test "x$OPENJDK_TARGET_OS" = xmacosx; then
+-    # No fontconfig support on windows or macosx
++  if test "x$OPENJDK_TARGET_OS" = xwindows || test "x$OPENJDK_TARGET_OS" = xmacosx || test "x$OPENJDK_TARGET_OS" = xandroid; then
++    # No fontconfig support on windows, macosx or android
+     NEEDS_LIB_FONTCONFIG=false
+   else
+     # All other instances need fontconfig, even if building headless only,
+diff --git a/make/autoconf/platform.m4 b/make/autoconf/platform.m4
+index 90d5d7956..3a1c80670 100644
+--- a/make/autoconf/platform.m4
++++ b/make/autoconf/platform.m4
+@@ -202,6 +202,10 @@ AC_DEFUN([PLATFORM_EXTRACT_VARS_FROM_OS],
+       VAR_OS=linux
+       VAR_OS_TYPE=unix
+       ;;
++    *android*)
++      VAR_OS=linux
++      VAR_OS_TYPE=unix
++      ;;
+     *darwin*)
+       VAR_OS=macosx
+       VAR_OS_TYPE=unix
+diff --git a/make/autoconf/toolchain.m4 b/make/autoconf/toolchain.m4
+index 8a08e86d5..cef968226 100644
+--- a/make/autoconf/toolchain.m4
++++ b/make/autoconf/toolchain.m4
+@@ -881,11 +881,14 @@ AC_DEFUN_ONCE([TOOLCHAIN_SETUP_BUILD_COMPILERS],
+ 
+     PATH="$OLDPATH"
+ 
+-    TOOLCHAIN_EXTRACT_COMPILER_VERSION(BUILD_CC, [BuildC])
+-    TOOLCHAIN_EXTRACT_COMPILER_VERSION(BUILD_CXX, [BuildC++])
+-    TOOLCHAIN_PREPARE_FOR_VERSION_COMPARISONS([BUILD_], [OPENJDK_BUILD_], [build ])
+-    TOOLCHAIN_EXTRACT_LD_VERSION(BUILD_LD, [build linker])
+-    TOOLCHAIN_PREPARE_FOR_LD_VERSION_COMPARISONS([BUILD_], [OPENJDK_BUILD_])
++    # xandroid
++    if test "x$OPENJDK_BUILD_OS" != "xlinux"; then
++      TOOLCHAIN_EXTRACT_COMPILER_VERSION(BUILD_CC, [BuildC])
++      TOOLCHAIN_EXTRACT_COMPILER_VERSION(BUILD_CXX, [BuildC++])
++      TOOLCHAIN_PREPARE_FOR_VERSION_COMPARISONS([BUILD_], [OPENJDK_BUILD_], [build ])
++      TOOLCHAIN_EXTRACT_LD_VERSION(BUILD_LD, [build linker])
++      TOOLCHAIN_PREPARE_FOR_LD_VERSION_COMPARISONS([BUILD_], [OPENJDK_BUILD_])
++    fi
+   else
+     # If we are not cross compiling, use the normal target compilers for
+     # building the build platform executables.
+diff --git a/make/common/Modules.gmk b/make/common/Modules.gmk
+index 1ec7bef6f..8612de99b 100644
+--- a/make/common/Modules.gmk
++++ b/make/common/Modules.gmk
+@@ -71,6 +71,10 @@ GENERATED_SRC_DIRS += \
+ TOP_SRC_DIRS += \
+     $(TOPDIR)/src \
+     #
++ifeq ($(OPENJDK_TARGET_OS), android)
++  SRC_SUBDIRS += linux/classes
++endif
++
+ 
+ SRC_SUBDIRS += $(OPENJDK_TARGET_OS)/classes
+ ifneq ($(OPENJDK_TARGET_OS), $(OPENJDK_TARGET_OS_TYPE))
+diff --git a/make/common/Utils.gmk b/make/common/Utils.gmk
+index b4bb949d3..164ab2202 100644
+--- a/make/common/Utils.gmk
++++ b/make/common/Utils.gmk
+@@ -193,6 +193,12 @@ MakeDir = \
+ isTargetOs = \
+   $(strip $(if $(filter $(OPENJDK_TARGET_OS), $1), true, false))
+ 
++ifeq ($(call isTargetOs, android), true)
++  # PATCH: Since Android is Linux, so Linux specific things are also built for Android.
++  isTargetOs = \
++    $(strip $(if $(filter $(OPENJDK_TARGET_OS), $1), true, $(if $(filter linux, $1), true, false)))
++endif
++
+ isTargetOsType = \
+   $(strip $(if $(filter $(OPENJDK_TARGET_OS_TYPE), $1), true, false))
+ 
+diff --git a/make/conf/branding.conf b/make/conf/branding.conf
+index 912e4f622..27fd26607 100644
+--- a/make/conf/branding.conf
++++ b/make/conf/branding.conf
+@@ -25,7 +25,7 @@
+ 
+ LAUNCHER_NAME=openjdk
+ PRODUCT_NAME=OpenJDK
+-PRODUCT_SUFFIX="Runtime Environment"
++PRODUCT_SUFFIX="Android Runtime Environment"
+ JDK_RC_PLATFORM_NAME=Platform
+ COMPANY_NAME=N/A
+ HOTSPOT_VM_DISTRO="OpenJDK"
+diff --git a/make/hotspot/lib/JvmOverrideFiles.gmk b/make/hotspot/lib/JvmOverrideFiles.gmk
+index 80f358204..75de0d076 100644
+--- a/make/hotspot/lib/JvmOverrideFiles.gmk
++++ b/make/hotspot/lib/JvmOverrideFiles.gmk
+@@ -61,7 +61,8 @@ ifeq ($(call isTargetOs, linux), true)
+       $(OPT_SPEED_SRC) \
+       #
+ 
+-  ifeq ($(call isTargetCpu, x86), true)
++  #ifeq ($(call isTargetCpu, x86), true)
++  ifeq (false, true)
+     # Performance measurements show that by compiling GC related code, we could
+     # significantly reduce the GC pause time on 32 bit Linux/Unix platforms by
+     # compiling without the PIC flag (-fPIC on linux).
+diff --git a/make/modules/java.desktop/Lib.gmk b/make/modules/java.desktop/Lib.gmk
+index 830e0553c..4f37c5a79 100644
+--- a/make/modules/java.desktop/Lib.gmk
++++ b/make/modules/java.desktop/Lib.gmk
+@@ -79,7 +79,7 @@ ifeq ($(call isTargetOs, aix), false)
+       LIBS_windows := advapi32.lib dsound.lib ole32.lib user32.lib winmm.lib, \
+   ))
+ 
+-  TARGETS += $(BUILD_LIBJSOUND)
++  # TARGETS += $(BUILD_LIBJSOUND)
+ endif
+ 
+ ifeq ($(call isTargetOs, macosx), true)
+diff --git a/make/modules/java.instrument/Lib.gmk b/make/modules/java.instrument/Lib.gmk
+index 4181cdf81..893e0f418 100644
+--- a/make/modules/java.instrument/Lib.gmk
++++ b/make/modules/java.instrument/Lib.gmk
+@@ -35,6 +35,9 @@ include LibCommon.gmk
+ $(eval $(call SetupJdkLibrary, BUILD_LIBINSTRUMENT, \
+     NAME := instrument, \
+     OPTIMIZATION := LOW, \
++    EXTRA_SRC := java.base:libtinyiconv, \
++    CXXFLAGS := $(CXXFLAGS_JDKLIB), \
++    LINK_TYPE := C++, \
+     CFLAGS := $(ICONV_CFLAGS), \
+     CFLAGS_windows := -Dstrcasecmp=stricmp, \
+     CFLAGS_debug := -DJPLIS_LOGGING, \
+diff --git a/make/modules/jdk.hotspot.agent/Lib.gmk b/make/modules/jdk.hotspot.agent/Lib.gmk
+index da02e0dab..e922d0c43 100644
+--- a/make/modules/jdk.hotspot.agent/Lib.gmk
++++ b/make/modules/jdk.hotspot.agent/Lib.gmk
+@@ -87,6 +87,7 @@ $(eval $(call SetupJdkLibrary, BUILD_LIBSAPROC, \
+     LIBS_windows := dbgeng.lib, \
+ ))
+ 
+-TARGETS += $(BUILD_LIBSAPROC)
++# Android: libsaproc does not build against bionic (no prstatus_t); skipped like FCL/AngelAuraMC jre25
++# TARGETS += $(BUILD_LIBSAPROC)
+ 
+ ################################################################################
+diff --git a/make/modules/jdk.jdwp.agent/Lib.gmk b/make/modules/jdk.jdwp.agent/Lib.gmk
+index ce58e145f..90cdec4da 100644
+--- a/make/modules/jdk.jdwp.agent/Lib.gmk
++++ b/make/modules/jdk.jdwp.agent/Lib.gmk
+@@ -53,6 +53,9 @@ TARGETS += $(BUILD_LIBDT_SOCKET)
+ $(eval $(call SetupJdkLibrary, BUILD_LIBJDWP, \
+     NAME := jdwp, \
+     OPTIMIZATION := LOW, \
++    EXTRA_SRC := java.base:libtinyiconv, \
++    CXXFLAGS := $(CXXFLAGS_JDKLIB), \
++    LINK_TYPE := C++, \
+     CFLAGS := -DJDWP_LOGGING $(ICONV_CFLAGS), \
+     LDFLAGS := $(ICONV_LDFLAGS), \
+     EXTRA_HEADER_DIRS := \
+diff --git a/src/hotspot/cpu/arm/icache_arm.cpp b/src/hotspot/cpu/arm/icache_arm.cpp
+index 53e982475..fc8fc1cbf 100644
+--- a/src/hotspot/cpu/arm/icache_arm.cpp
++++ b/src/hotspot/cpu/arm/icache_arm.cpp
+@@ -30,7 +30,7 @@
+ 
+ 
+ static int icache_flush(address addr, int lines, int magic) {
+-  __builtin___clear_cache(addr, addr + (lines << ICache::log2_line_size));
++  __builtin___clear_cache((char*) addr, (char*) (addr + (lines << ICache::log2_line_size)));
+   return magic;
+ }
+ 
+diff --git a/src/hotspot/os/linux/gc/z/zNUMA_linux.cpp b/src/hotspot/os/linux/gc/z/zNUMA_linux.cpp
+index 3245d07ca..f49054681 100644
+--- a/src/hotspot/os/linux/gc/z/zNUMA_linux.cpp
++++ b/src/hotspot/os/linux/gc/z/zNUMA_linux.cpp
+@@ -138,7 +138,7 @@ class ZNUMAConverter {
+ static ZNUMAConverter z_numa_converter;
+ 
+ void ZNUMA::pd_initialize() {
+-  _enabled = UseNUMA;
++  _enabled = false;
+ 
+   if (UseNUMA) {
+     z_numa_converter.initialize();
+diff --git a/src/hotspot/os/linux/os_linux.cpp b/src/hotspot/os/linux/os_linux.cpp
+index ba48f2b4e..870140c47 100644
+--- a/src/hotspot/os/linux/os_linux.cpp
++++ b/src/hotspot/os/linux/os_linux.cpp
+@@ -136,10 +136,10 @@
+ 
+ #define MAX_PATH    (2 * K)
+ 
+-#ifdef MUSL_LIBC
++#if defined(MUSL_LIBC) || defined(__ANDROID__)
+ // dlvsym is not a part of POSIX
+ // and musl libc doesn't implement it.
+-static void *dlvsym(void *handle,
++void *dlvsym(void *handle,
+                     const char *symbol,
+                     const char *version) {
+    // load the latest version of symbol
+@@ -211,6 +211,8 @@ static malloc_info_func_t g_malloc_info = nullptr;
+ // avoid this
+ static bool suppress_primordial_thread_resolution = false;
+ 
++bool read_so_path_from_maps(const char* so_name, char* buf, int buflen);
++
+ // utility functions
+ 
+ bool os::is_containerized() {
+@@ -536,10 +538,12 @@ bool os::Linux::get_tick_information(CPUPerfTicks* pticks, int which_logical_cpu
+ 
+ #ifndef SYS_gettid
+ // i386: 224, amd64: 186
+-  #if defined(__i386__)
++  #if defined(__i386__) || defined(__arm__)
+     #define SYS_gettid 224
+   #elif defined(__amd64__)
+     #define SYS_gettid 186
++  #elif defined(__arm64__) || defined(__aarch64__)
++    #define SYS_gettid 178
+   #else
+     #error "Define SYS_gettid for this architecture"
+   #endif
+@@ -728,6 +732,7 @@ void os::init_system_properties_values() {
+ // detecting pthread library
+ 
+ void os::Linux::libpthread_init() {
++#ifndef __ANDROID__
+   // Save glibc and pthread version strings.
+ #if !defined(_CS_GNU_LIBC_VERSION) || \
+     !defined(_CS_GNU_LIBPTHREAD_VERSION)
+@@ -752,6 +757,9 @@ void os::Linux::libpthread_init() {
+   confstr(_CS_GNU_LIBPTHREAD_VERSION, str, n);
+   os::Linux::set_libpthread_version(str);
+ #endif
++#else
++  os::Linux::set_libpthread_version("NPTL");
++#endif
+ }
+ 
+ /////////////////////////////////////////////////////////////////////////////
+@@ -1551,7 +1559,13 @@ int os::current_process_id() {
+ 
+ // This must be hard coded because it's the system's temporary
+ // directory not the java application's temp directory, ala java.io.tmpdir.
+-const char* os::get_temp_directory() { return "/tmp"; }
++const char* os::get_temp_directory() {
++#ifndef __ANDROID__
++  return "/tmp";
++#else
++  return "/data/tmp";
++#endif
++}
+ 
+ // check if addr is inside libjvm.so
+ bool os::address_is_in_vm(address addr) {
+@@ -1626,6 +1640,30 @@ bool os::dll_address_to_library_name(address addr, char* buf,
+   return false;
+ }
+ 
++bool read_so_path_from_maps(const char* so_name, char* buf, int buflen) {
++  FILE *fp = fopen("/proc/self/maps", "r");
++  assert(fp, "Failed to open /proc/self/maps");
++  if (!fp) {
++    return false;
++  }
++
++  char maps_buffer[2048];
++  while (fgets(maps_buffer, 2048, fp) != NULL) {
++    if (strstr(maps_buffer, so_name) == NULL) {
++      continue;
++    }
++
++    char *so_path = strchr(maps_buffer, '/');
++    so_path[strlen(so_path) - 1] = '\0'; // Cut trailing \n
++    jio_snprintf(buf, buflen, "%s", so_path);
++    fclose(fp);
++    return true;
++  }
++
++  fclose(fp);
++  return false;
++}
++
+ // Remember the stack's state. The Linux dynamic linker will change
+ // the stack to 'executable' at most once, so we must safepoint only once.
+ bool os::Linux::_stack_is_executable = false;
+@@ -2025,6 +2063,7 @@ void * os::Linux::dll_load_in_vmthread(const char *filename, char *ebuf,
+ }
+ 
+ const char* os::Linux::dll_path(void* lib) {
++#ifdef RTLD_DI_LINKMAP
+   struct link_map *lmap;
+   const char* l_path = nullptr;
+   assert(lib != nullptr, "dll_path parameter must not be null");
+@@ -2034,6 +2073,9 @@ const char* os::Linux::dll_path(void* lib) {
+     l_path = lmap->l_name;
+   }
+   return l_path;
++#else
++  return NULL;
++#endif
+ }
+ 
+ static unsigned count_newlines(const char* s) {
+@@ -3164,7 +3206,8 @@ void os::Linux::sched_getcpu_init() {
+   }
+ 
+   if (sched_getcpu() == -1) {
+-    vm_exit_during_initialization("getcpu(2) system call not supported by kernel");
++    // vm_exit_during_initialization
++    warning("getcpu(2) system call not supported by kernel");
+   }
+ }
+ 
+@@ -3195,14 +3238,8 @@ static bool numa_syscall_check() {
+   // Especially in dockers, get_mempolicy is not allowed with the default configuration. So it's necessary
+   // to check whether the syscalls are available. Currently, only get_mempolicy is checked since checking
+   // others like mbind would cause unexpected side effects.
+-#ifdef SYS_get_mempolicy
+-  int dummy = 0;
+-  if (syscall(SYS_get_mempolicy, &dummy, nullptr, 0, (void*)&dummy, 3) == -1) {
+-    return false;
+-  }
+-#endif
+ 
+-  return true;
++  return false;
+ }
+ 
+ bool os::Linux::libnuma_init() {
+@@ -5109,7 +5146,46 @@ bool os::is_thread_cpu_time_supported() {
+ // Linux doesn't yet have a (official) notion of processor sets,
+ // so just return the system wide load average.
+ int os::loadavg(double loadavg[], int nelem) {
+-  return ::getloadavg(loadavg, nelem);
++#ifndef __ANDROID__
++   return ::getloadavg(loadavg, nelem);
++#else
++/*
++ * Copyright (C) 2018 The Android Open Source Project
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ *  * Redistributions of source code must retain the above copyright
++ *    notice, this list of conditions and the following disclaimer.
++ *  * Redistributions in binary form must reproduce the above copyright
++ *    notice, this list of conditions and the following disclaimer in
++ *    the documentation and/or other materials provided with the
++ *    distribution.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
++ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
++ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
++ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
++ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
++ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
++ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
++ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
++ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
++ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
++ * SUCH DAMAGE.
++ */
++
++  if (nelem < 0) return -1;
++  if (nelem > 3) nelem = 3;
++  struct sysinfo si;
++  if (sysinfo(&si) == -1) return -1;
++  for (int i = 0; i < nelem; ++i) {
++    loadavg[i] = static_cast<double>(si.loads[i]) / static_cast<double>(1 << SI_LOAD_SHIFT);
++  }
++  return nelem;
++#endif
+ }
+ 
+ // Get the default path to the core file
+diff --git a/src/hotspot/os/linux/os_perf_linux.cpp b/src/hotspot/os/linux/os_perf_linux.cpp
+index c0e863ed2..cff4b7d4c 100644
+--- a/src/hotspot/os/linux/os_perf_linux.cpp
++++ b/src/hotspot/os/linux/os_perf_linux.cpp
+@@ -36,7 +36,18 @@
+ #include <dlfcn.h>
+ #include <errno.h>
+ #include <fcntl.h>
++#ifndef __ANDROID__
+ #include <ifaddrs.h>
++#else
++#include <sys/cdefs.h>
++#include <netinet/in.h>
++#include <sys/socket.h>
++#include <linux/if_packet.h>
++#include <linux/netlink.h>
++#include <linux/rtnetlink.h>
++#include <net/if.h>
++#include <stdint.h>
++#endif
+ #include <limits.h>
+ #include <pthread.h>
+ #include <stdarg.h>
+@@ -47,6 +58,299 @@
+ #include <sys/types.h>
+ #include <unistd.h>
+ 
++#ifdef __ANDROID__
++/*
++ * Copyright (C) 2015 The Android Open Source Project
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ *  * Redistributions of source code must retain the above copyright
++ *    notice, this list of conditions and the following disclaimer.
++ *  * Redistributions in binary form must reproduce the above copyright
++ *    notice, this list of conditions and the following disclaimer in
++ *    the documentation and/or other materials provided with the
++ *    distribution.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
++ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
++ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
++ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
++ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
++ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
++ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
++ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
++ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
++ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
++ * SUCH DAMAGE.
++ */
++
++__BEGIN_DECLS
++
++/**
++ * Returned by getifaddrs() and freed by freeifaddrs().
++ */
++struct ifaddrs {
++  /** Pointer to the next element in the linked list. */
++  struct ifaddrs* ifa_next;
++
++  /** Interface name. */
++  char* ifa_name;
++
++  /** Interface flags (like `SIOCGIFFLAGS`). */
++  unsigned int ifa_flags;
++
++  /** Interface address. */
++  struct sockaddr* ifa_addr;
++
++  /** Interface netmask. */
++  struct sockaddr* ifa_netmask;
++
++  union {
++    /** Interface broadcast address (if IFF_BROADCAST is set). */
++    struct sockaddr* ifu_broadaddr;
++
++    /** Interface destination address (if IFF_POINTOPOINT is set). */
++    struct sockaddr* ifu_dstaddr;
++  } ifa_ifu;
++
++  /** Unused. */
++  void* ifa_data;
++};
++
++/** Synonym for `ifa_ifu.ifu_broadaddr` in `struct ifaddrs`. */
++#define ifa_broadaddr ifa_ifu.ifu_broadaddr
++
++/** Synonym for `ifa_ifu.ifu_dstaddr` in `struct ifaddrs`. */
++#define ifa_dstaddr ifa_ifu.ifu_dstaddr
++
++/**
++ * [getifaddrs(3)](http://man7.org/linux/man-pages/man3/getifaddrs.3.html) creates a linked list
++ * of `struct ifaddrs`. The list must be freed by freeifaddrs().
++ *
++ * Returns 0 and stores the list in `*__list_ptr` on success,
++ * and returns -1 and sets `errno` on failure.
++ *
++ * Available since API level 24.
++ */
++int getifaddrs(struct ifaddrs** __list_ptr); // __INTRODUCED_IN(24);
++
++/**
++ * [freeifaddrs(3)](http://man7.org/linux/man-pages/man3/freeifaddrs.3.html) frees a linked list
++ * of `struct ifaddrs` returned by getifaddrs().
++ *
++ * Available since API level 24.
++ */
++void freeifaddrs(struct ifaddrs* __ptr); // __INTRODUCED_IN(24);
++
++__END_DECLS
++
++#define nullptr 0
++
++// The public ifaddrs struct is full of pointers. Rather than track several
++// different allocations, we use a maximally-sized structure with the public
++// part at offset 0, and pointers into its hidden tail.
++struct ifaddrs_storage {
++  // Must come first, so that `ifaddrs_storage` is-a `ifaddrs`.
++  ifaddrs ifa;
++  // The interface index, so we can match RTM_NEWADDR messages with
++  // earlier RTM_NEWLINK messages (to copy the interface flags).
++  int interface_index;
++  // Storage for the pointers in `ifa`.
++  sockaddr_storage addr;
++  sockaddr_storage netmask;
++  sockaddr_storage ifa_ifu;
++  char name[IFNAMSIZ + 1];
++  // Netlink gives us the address family in the header, and the
++  // sockaddr_in or sockaddr_in6 bytes as the payload. We need to
++  // stitch the two bits together into the sockaddr that's part of
++  // our portable interface.
++  void SetAddress(int family, const void* data, size_t byteCount) {
++      addr.ss_family = family;
++      memcpy(SockaddrBytes(family, &addr), data, byteCount);
++      ifa.ifa_addr = reinterpret_cast<sockaddr*>(&addr);
++  }
++  void SetBroadcastAddress(int family, const void* data, size_t byteCount) {
++      ifa_ifu.ss_family = family;
++      memcpy(SockaddrBytes(family, &ifa_ifu), data, byteCount);
++      ifa.ifa_dstaddr = reinterpret_cast<sockaddr*>(&ifa_ifu);
++  }
++  // Netlink gives us the prefix length as a bit count. We need to turn
++  // that into a BSD-compatible netmask represented by a sockaddr*.
++  void SetNetmask(int family, size_t prefix_length) {
++      // ...and work out the netmask from the prefix length.
++      netmask.ss_family = family;
++      uint8_t* dst = SockaddrBytes(family, &netmask);
++      memset(dst, 0xff, prefix_length / 8);
++      if ((prefix_length % 8) != 0) {
++        dst[prefix_length/8] = (0xff << (8 - (prefix_length % 8)));
++      }
++      ifa.ifa_netmask = reinterpret_cast<sockaddr*>(&netmask);
++  }
++  void SetPacketAttributes(int ifindex, unsigned short hatype, unsigned char halen) {
++    sockaddr_ll* sll = reinterpret_cast<sockaddr_ll*>(&addr);
++    sll->sll_ifindex = ifindex;
++    sll->sll_hatype = hatype;
++    sll->sll_halen = halen;
++  }
++ private:
++  // Returns a pointer to the first byte in the address data (which is
++  // stored in network byte order).
++  uint8_t* SockaddrBytes(int family, sockaddr_storage* ss) {
++    if (family == AF_INET) {
++      sockaddr_in* ss4 = reinterpret_cast<sockaddr_in*>(ss);
++      return reinterpret_cast<uint8_t*>(&ss4->sin_addr);
++    } else if (family == AF_INET6) {
++      sockaddr_in6* ss6 = reinterpret_cast<sockaddr_in6*>(ss);
++      return reinterpret_cast<uint8_t*>(&ss6->sin6_addr);
++    } else if (family == AF_PACKET) {
++      sockaddr_ll* sll = reinterpret_cast<sockaddr_ll*>(ss);
++      return reinterpret_cast<uint8_t*>(&sll->sll_addr);
++    }
++    return nullptr;
++  }
++};
++ifaddrs_storage* new_ifaddrs_storage(ifaddrs** list) {
++  ifaddrs_storage *storage;
++  memset(storage, 0, sizeof(*storage));
++  // push_front onto `list`.
++  storage->ifa.ifa_next = *list;
++  *list = reinterpret_cast<ifaddrs*>(storage);
++  return storage;
++}
++#if !defined(__clang__)
++// GCC gets confused by NLMSG_DATA and doesn't realize that the old-style
++// cast is from a system header and should be ignored.
++#pragma GCC diagnostic ignored "-Wold-style-cast"
++#endif
++static void __handle_netlink_response(ifaddrs** out, nlmsghdr* hdr) {
++  if (hdr->nlmsg_type == RTM_NEWLINK) {
++    ifinfomsg* ifi = reinterpret_cast<ifinfomsg*>(NLMSG_DATA(hdr));
++    // Create a new ifaddr entry, and set the interface index and flags.
++    ifaddrs_storage* new_addr = new_ifaddrs_storage(out);
++    new_addr->interface_index = ifi->ifi_index;
++    new_addr->ifa.ifa_flags = ifi->ifi_flags;
++    // Go through the various bits of information and find the name.
++    rtattr* rta = IFLA_RTA(ifi);
++    size_t rta_len = IFLA_PAYLOAD(hdr);
++    while (RTA_OK(rta, rta_len)) {
++      if (rta->rta_type == IFLA_ADDRESS) {
++          if (RTA_PAYLOAD(rta) < sizeof(new_addr->addr)) {
++            new_addr->SetAddress(AF_PACKET, RTA_DATA(rta), RTA_PAYLOAD(rta));
++            new_addr->SetPacketAttributes(ifi->ifi_index, ifi->ifi_type, RTA_PAYLOAD(rta));
++          }
++      } else if (rta->rta_type == IFLA_BROADCAST) {
++          if (RTA_PAYLOAD(rta) < sizeof(new_addr->ifa_ifu)) {
++            new_addr->SetBroadcastAddress(AF_PACKET, RTA_DATA(rta), RTA_PAYLOAD(rta));
++            new_addr->SetPacketAttributes(ifi->ifi_index, ifi->ifi_type, RTA_PAYLOAD(rta));
++          }
++      } else if (rta->rta_type == IFLA_IFNAME) {
++          if (RTA_PAYLOAD(rta) < sizeof(new_addr->name)) {
++            memcpy(new_addr->name, RTA_DATA(rta), RTA_PAYLOAD(rta));
++            new_addr->ifa.ifa_name = new_addr->name;
++          }
++      }
++      rta = RTA_NEXT(rta, rta_len);
++    }
++  } else if (hdr->nlmsg_type == RTM_NEWADDR) {
++    ifaddrmsg* msg = reinterpret_cast<ifaddrmsg*>(NLMSG_DATA(hdr));
++    // We should already know about this from an RTM_NEWLINK message.
++    const ifaddrs_storage* addr = reinterpret_cast<const ifaddrs_storage*>(*out);
++    while (addr != nullptr && addr->interface_index != static_cast<int>(msg->ifa_index)) {
++      addr = reinterpret_cast<const ifaddrs_storage*>(addr->ifa.ifa_next);
++    }
++    // If this is an unknown interface, ignore whatever we're being told about it.
++    if (addr == nullptr) return;
++    // Create a new ifaddr entry and copy what we already know.
++    ifaddrs_storage* new_addr = new_ifaddrs_storage(out);
++    // We can just copy the name rather than look for IFA_LABEL.
++    strcpy(new_addr->name, addr->name);
++    new_addr->ifa.ifa_name = new_addr->name;
++    new_addr->ifa.ifa_flags = addr->ifa.ifa_flags;
++    new_addr->interface_index = addr->interface_index;
++    // Go through the various bits of information and find the address
++    // and any broadcast/destination address.
++    rtattr* rta = IFA_RTA(msg);
++    size_t rta_len = IFA_PAYLOAD(hdr);
++    while (RTA_OK(rta, rta_len)) {
++      if (rta->rta_type == IFA_ADDRESS) {
++        if (msg->ifa_family == AF_INET || msg->ifa_family == AF_INET6) {
++          new_addr->SetAddress(msg->ifa_family, RTA_DATA(rta), RTA_PAYLOAD(rta));
++          new_addr->SetNetmask(msg->ifa_family, msg->ifa_prefixlen);
++        }
++      } else if (rta->rta_type == IFA_BROADCAST) {
++        if (msg->ifa_family == AF_INET || msg->ifa_family == AF_INET6) {
++          new_addr->SetBroadcastAddress(msg->ifa_family, RTA_DATA(rta), RTA_PAYLOAD(rta));
++        }
++      }
++      rta = RTA_NEXT(rta, rta_len);
++    }
++  }
++}
++static bool __send_netlink_request(int fd, int type) {
++  struct NetlinkMessage {
++    nlmsghdr hdr;
++    rtgenmsg msg;
++  } request;
++  memset(&request, 0, sizeof(request));
++  request.hdr.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST;
++  request.hdr.nlmsg_type = type;
++  request.hdr.nlmsg_len = sizeof(request);
++  request.msg.rtgen_family = AF_UNSPEC; // All families.
++  return (TEMP_FAILURE_RETRY(send(fd, &request, sizeof(request), 0)) == sizeof(request));
++}
++static bool __read_netlink_responses(int fd, ifaddrs** out, char* buf, size_t buf_len) {
++  ssize_t bytes_read;
++  // Read through all the responses, handing interesting ones to __handle_netlink_response.
++  while ((bytes_read = TEMP_FAILURE_RETRY(recv(fd, buf, buf_len, 0))) > 0) {
++    nlmsghdr* hdr = reinterpret_cast<nlmsghdr*>(buf);
++    for (; NLMSG_OK(hdr, static_cast<size_t>(bytes_read)); hdr = NLMSG_NEXT(hdr, bytes_read)) {
++      if (hdr->nlmsg_type == NLMSG_DONE) return true;
++      if (hdr->nlmsg_type == NLMSG_ERROR) return false;
++      __handle_netlink_response(out, hdr);
++    }
++  }
++  // We only get here if recv fails before we see a NLMSG_DONE.
++  return false;
++}
++int getifaddrs(ifaddrs** out) {
++  // Make cleanup easy.
++  *out = nullptr;
++  // The kernel keeps packets under 8KiB (NLMSG_GOODSIZE),
++  // but that's a bit too large to go on the stack.
++  size_t buf_len = 8192;
++  char* buf = NEW_C_HEAP_ARRAY(char, buf_len, mtInternal);
++  if (buf == nullptr) return -1;
++  // Open the netlink socket and ask for all the links and addresses.
++  int fd = socket(PF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, NETLINK_ROUTE);
++  bool okay = fd != -1 &&
++      __send_netlink_request(fd, RTM_GETLINK) && __read_netlink_responses(fd, out, buf, buf_len) &&
++      __send_netlink_request(fd, RTM_GETADDR) && __read_netlink_responses(fd, out, buf, buf_len);
++  if (!okay) {
++    freeifaddrs(*out);
++    // Ensure that callers crash if they forget to check for success.
++    *out = nullptr;
++  }
++  {
++    int saved_errno = errno;
++    close(fd);
++    FREE_C_HEAP_ARRAY(buf);
++    errno = saved_errno;
++  }
++  return okay ? 0 : -1;
++}
++void freeifaddrs(ifaddrs* list) {
++  while (list != nullptr) {
++    ifaddrs* current = list;
++    list = list->ifa_next;
++    free(current);
++  }
++}
++#endif
++
++
+ /**
+    /proc/[number]/stat
+               Status information about the process.  This is used by ps(1).  It is defined in /usr/src/linux/fs/proc/array.c.
+diff --git a/src/hotspot/os/posix/os_posix.cpp b/src/hotspot/os/posix/os_posix.cpp
+index 1eee76b46..cb5dd2a22 100644
+--- a/src/hotspot/os/posix/os_posix.cpp
++++ b/src/hotspot/os/posix/os_posix.cpp
+@@ -85,7 +85,9 @@
+ #include <sys/wait.h>
+ #include <time.h>
+ #include <unistd.h>
++#ifndef __ANDROID__
+ #include <utmpx.h>
++#endif
+ 
+ #ifdef __APPLE__
+   #include <crt_externs.h>
+@@ -566,6 +568,7 @@ void os::Posix::print_load_average(outputStream* st) {
+ // unfortunately it does not work on macOS and Linux because the utx chain has no entry
+ // for reboot at least on my test machines
+ void os::Posix::print_uptime_info(outputStream* st) {
++#ifndef __ANDROID__
+   int bootsec = -1;
+   time_t currsec = time(nullptr);
+   struct utmpx* ent;
+@@ -580,6 +583,7 @@ void os::Posix::print_uptime_info(outputStream* st) {
+   if (bootsec != -1) {
+     os::print_dhm(st, "OS uptime:", currsec-bootsec);
+   }
++#endif
+ }
+ 
+ static void print_rlimit(outputStream* st, const char* msg,
+@@ -1149,6 +1153,25 @@ void os::jvm_path(char *buf, jint buflen) {
+   }
+   fname = dli_fname;
+ #endif // AIX
++#ifdef __ANDROID__
++  if (fname[0] == '\0') {
++    return;
++  }
++  if (strchr(fname, '/') == nullptr) {
++    extern bool read_so_path_from_maps(const char* so_name, char* buf, int buflen);
++    bool ok = read_so_path_from_maps(fname, buf, buflen);
++    assert(ok, "unable to turn relative libjvm.so path into absolute");
++    if (ok) {
++      strncpy(saved_jvm_path, buf, MAXPATHLEN);
++      saved_jvm_path[MAXPATHLEN - 1] = '\0';
++    }
++    return;
++  }
++  snprintf(buf, buflen, "%s", fname);
++  strncpy(saved_jvm_path, buf, MAXPATHLEN);
++  saved_jvm_path[MAXPATHLEN - 1] = '\0';
++  return;
++#endif // __ANDROID__
+   char* rp = nullptr;
+   if (fname[0] != '\0') {
+     rp = os::realpath(fname, buf, buflen);
+@@ -2152,11 +2175,31 @@ int os::fork_and_exec(const char* cmd) {
+   const char* argv[4] = {"sh", "-c", cmd, nullptr};
+   pid_t pid = -1;
+   char** env = os::get_environ();
++#ifndef __ANDROID__
+   // Note: cast is needed because posix_spawn() requires - for compatibility with ancient
+   // C-code - a non-const argv/envp pointer array. But it is fine to hand in literal
+   // strings and just cast the constness away. See also ProcessImpl_md.c.
+   int rc = ::posix_spawn(&pid, "/bin/sh", nullptr, nullptr, (char**) argv, env);
+   if (rc == 0) {
++#else
++  pid = ::fork();
++
++  if (pid < 0) {
++    // fork failed
++    return -1;
++
++  } else if (pid == 0) {
++    // child process
++
++    ::execve("/bin/sh", (char* const*)argv, env);
++
++    // execve failed
++    ::_exit(-1);
++
++  } else  {
++    // copied from J2SE ..._waitForProcessExit() in UNIXProcess_md.c; we don't
++    // care about the actual exit code, for now.
++#endif
+     int status;
+     // Wait for the child process to exit.  This returns immediately if
+     // the child has already exited. */
+@@ -2181,9 +2224,11 @@ int os::fork_and_exec(const char* cmd) {
+       // Unknown exit code; pass it through
+       return status;
+     }
++#ifndef __ANDROID__
+   } else {
+     // Don't log, we are inside error handling
+     return -1;
++#endif
+   }
+ }
+ 
+diff --git a/src/hotspot/os_cpu/linux_aarch64/javaThread_linux_aarch64.hpp b/src/hotspot/os_cpu/linux_aarch64/javaThread_linux_aarch64.hpp
+index c6e012ecf..d4f956756 100644
+--- a/src/hotspot/os_cpu/linux_aarch64/javaThread_linux_aarch64.hpp
++++ b/src/hotspot/os_cpu/linux_aarch64/javaThread_linux_aarch64.hpp
+@@ -47,6 +47,8 @@
+   bool pd_get_top_frame(frame* fr_addr, void* ucontext, bool isInJava);
+ public:
+ 
+-  static Thread *aarch64_get_thread_helper();
++  static Thread *aarch64_get_thread_helper() {
++    return Thread::current();
++  }
+ 
+ #endif // OS_CPU_LINUX_AARCH64_JAVATHREAD_LINUX_AARCH64_HPP
+diff --git a/src/hotspot/os_cpu/linux_aarch64/threadLS_linux_aarch64.S b/src/hotspot/os_cpu/linux_aarch64/threadLS_linux_aarch64.S
+index 33be49019..7f6ad8be5 100644
+--- a/src/hotspot/os_cpu/linux_aarch64/threadLS_linux_aarch64.S
++++ b/src/hotspot/os_cpu/linux_aarch64/threadLS_linux_aarch64.S
+@@ -22,6 +22,7 @@
+ 
+ #include "defs.S.inc"
+ 
++#ifndef __ANDROID__
+         // JavaThread::aarch64_get_thread_helper()
+         //
+         // Return the current thread pointer in x0.
+@@ -44,7 +45,7 @@ DECLARE_FUNC(_ZN10JavaThread25aarch64_get_thread_helperEv):
+         ret
+ 
+         .size _ZN10JavaThread25aarch64_get_thread_helperEv, .-_ZN10JavaThread25aarch64_get_thread_helperEv
+-
++#endif
+ /* Emit .note.gnu.property section in case of PAC or BTI being enabled.
+  * For more details see "ELF for the Arm(R) 64-bit Architecture (AArch64)".
+  * https://github.com/ARM-software/abi-aa/blob/main/aaelf64/aaelf64.rst
+diff --git a/src/hotspot/os_cpu/linux_arm/fpu_control.h b/src/hotspot/os_cpu/linux_arm/fpu_control.h
+new file mode 100644
+index 000000000..745243d62
+--- /dev/null
++++ b/src/hotspot/os_cpu/linux_arm/fpu_control.h
+@@ -0,0 +1,59 @@
++/* FPU control word definitions.  ARM VFP version.
++   Copyright (C) 2004-2019 Free Software Foundation, Inc.
++   This file is part of the GNU C Library.
++   The GNU C Library is free software; you can redistribute it and/or
++   modify it under the terms of the GNU Lesser General Public
++   License as published by the Free Software Foundation; either
++   version 2.1 of the License, or (at your option) any later version.
++   The GNU C Library is distributed in the hope that it will be useful,
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++   Lesser General Public License for more details.
++   You should have received a copy of the GNU Lesser General Public
++   License along with the GNU C Library.  If not, see
++   <http://www.gnu.org/licenses/>.  */
++#ifndef _FPU_CONTROL_H
++#define _FPU_CONTROL_H
++#if !(defined(_LIBC) && !defined(_LIBC_TEST)) && defined(__SOFTFP__)
++#define _FPU_RESERVED 0xffffffff
++#define _FPU_DEFAULT  0x00000000
++typedef unsigned int fpu_control_t;
++#define _FPU_GETCW(cw) (cw) = 0
++#define _FPU_SETCW(cw) (void) (cw)
++extern fpu_control_t __fpu_control;
++#else
++/* masking of interrupts */
++#define _FPU_MASK_IM        0x00000100        /* invalid operation */
++#define _FPU_MASK_ZM        0x00000200        /* divide by zero */
++#define _FPU_MASK_OM        0x00000400        /* overflow */
++#define _FPU_MASK_UM        0x00000800        /* underflow */
++#define _FPU_MASK_PM        0x00001000        /* inexact */
++#define _FPU_MASK_NZCV        0xf0000000        /* NZCV flags */
++#define _FPU_MASK_RM        0x00c00000        /* rounding mode */
++#define _FPU_MASK_EXCEPT 0x00001f1f        /* all exception flags */
++/* Some bits in the FPSCR are not yet defined.  They must be preserved when
++   modifying the contents.  */
++#define _FPU_RESERVED        0x00086060
++#define _FPU_DEFAULT    0x00000000
++/* Default + exceptions enabled.  */
++#define _FPU_IEEE        (_FPU_DEFAULT | 0x00001f00)
++/* Type of the control word.  */
++typedef unsigned int fpu_control_t;
++/* Macros for accessing the hardware control word.  */
++#ifdef __SOFTFP__
++/* This is fmrx %0, fpscr.  */
++# define _FPU_GETCW(cw) \
++  __asm__ __volatile__ ("mrc p10, 7, %0, cr1, cr0, 0" : "=r" (cw))
++/* This is fmxr fpscr, %0.  */
++# define _FPU_SETCW(cw) \
++  __asm__ __volatile__ ("mcr p10, 7, %0, cr1, cr0, 0" : : "r" (cw))
++#else
++# define _FPU_GETCW(cw) \
++  __asm__ __volatile__ ("vmrs %0, fpscr" : "=r" (cw))
++# define _FPU_SETCW(cw) \
++  __asm__ __volatile__ ("vmsr fpscr, %0" : : "r" (cw))
++#endif
++/* Default control word set at startup.  */
++extern fpu_control_t __fpu_control;
++#endif /* __SOFTFP__ */
++#endif /* _FPU_CONTROL_H */
+diff --git a/src/hotspot/os_cpu/linux_arm/linux_arm_32.S b/src/hotspot/os_cpu/linux_arm/linux_arm_32.S
+index a866858da..db3a44c71 100644
+--- a/src/hotspot/os_cpu/linux_arm/linux_arm_32.S
++++ b/src/hotspot/os_cpu/linux_arm/linux_arm_32.S
+@@ -66,7 +66,7 @@ dw_f2b_loop_32:
+         stmia to!, {r3 - r9, ip}
+         bgt     dw_f2b_loop_32
+ dw_f2b_loop_32_finish:
+-        addlts  r2, #32
++        addslt  r2, #32
+         beq     disjoint_words_finish
+         cmp     r2, #16
+         blt	disjoint_words_small
+@@ -114,7 +114,7 @@ cw_f2b_loop_32:
+         stmia to!, {r3 - r9, ip}
+         bgt     cw_f2b_loop_32
+ cw_f2b_loop_32_finish:
+-        addlts  r2, #32
++        addslt  r2, #32
+         beq     conjoint_words_finish
+         cmp     r2, #16
+         blt	conjoint_words_small
+@@ -147,7 +147,7 @@ cw_b2f_loop_32:
+         stmdb to!, {r3-r9,ip}
+         bgt     cw_b2f_loop_32
+ cw_b2f_loop_32_finish:
+-        addlts  r2, #32
++        addslt  r2, #32
+         beq     conjoint_words_finish
+         cmp     r2, #16
+         blt	cw_b2f_copy_small
+@@ -199,7 +199,7 @@ cs_f2b_loop_32:
+         stmia to!, {r3 - r9, ip}
+         bgt     cs_f2b_loop_32
+ cs_f2b_loop_32_finish:
+-        addlts  r2, #32
++        addslt  r2, #32
+         beq     conjoint_shorts_finish
+         movs    r6, r2, lsr #3
+         .align 3
+@@ -215,11 +215,11 @@ cs_f2b_4:
+         beq     conjoint_shorts_finish
+         cmp     r2, #4
+         ldrh    r3, [from], #2
+-        ldrgeh  r4, [from], #2
+-        ldrgth  r5, [from], #2
++        ldrhge  r4, [from], #2
++        ldrhgt  r5, [from], #2
+         strh    r3, [to], #2
+-        strgeh  r4, [to], #2
+-        strgth  r5, [to], #2
++        strhge  r4, [to], #2
++        strhgt  r5, [to], #2
+         b       conjoint_shorts_finish
+ 
+         # Destination not aligned
+@@ -277,11 +277,11 @@ cs_f2b_4_u:
+         beq     conjoint_shorts_finish
+         cmp     r2, #4
+         ldrh    r3, [from], #2
+-        ldrgeh  r4, [from], #2
+-        ldrgth  r5, [from], #2
++        ldrhge  r4, [from], #2
++        ldrhgt  r5, [from], #2
+         strh    r3, [to], #2
+-        strgeh  r4, [to], #2
+-        strgth  r5, [to], #2
++        strhge  r4, [to], #2
++        strhgt  r5, [to], #2
+         b       conjoint_shorts_finish
+ 
+         # Src and dest overlap, copy in a descending order
+@@ -304,7 +304,7 @@ cs_b2f_loop_32:
+         stmdb to!, {r3-r9,ip}
+         bgt     cs_b2f_loop_32
+ cs_b2f_loop_32_finish:
+-        addlts  r2, #32
++        addslt  r2, #32
+         beq     conjoint_shorts_finish
+         cmp     r2, #24
+         blt     cs_b2f_16
+@@ -330,11 +330,11 @@ cs_b2f_8:
+ cs_b2f_all_copy:
+         cmp     r2, #4
+         ldrh    r3, [from, #-2]!
+-        ldrgeh  r4, [from, #-2]!
+-        ldrgth  r5, [from, #-2]!
++        ldrhge  r4, [from, #-2]!
++        ldrhgt  r5, [from, #-2]!
+         strh    r3, [to, #-2]!
+-        strgeh  r4, [to, #-2]!
+-        strgth  r5, [to, #-2]!
++        strhge  r4, [to, #-2]!
++        strhgt  r5, [to, #-2]!
+         b       conjoint_shorts_finish
+ 
+         # Destination not aligned
+@@ -369,7 +369,7 @@ cs_b2f_16_loop_u:
+         bgt     cs_b2f_16_loop_u
+         beq     conjoint_shorts_finish
+ cs_b2f_16_loop_u_finished:
+-        addlts  r2, #16
++        addslt  r2, #16
+         ldr     r3, [from]
+         cmp     r2, #10
+         blt     cs_b2f_2_u_loop
+@@ -432,7 +432,7 @@ cl_f2b_loop_32:
+         stmia to!, {r3 - r9, ip}
+         bgt     cl_f2b_loop_32
+ cl_f2b_loop_32_finish:
+-        addlts  r2, #32
++        addslt  r2, #32
+         beq     conjoint_longs_finish
+ conjoint_longs_small:
+         cmp     r2, #16
+@@ -465,7 +465,7 @@ cl_b2f_loop_32:
+         stmdb 	to!, {r3 - r9, ip}
+         bgt     cl_b2f_loop_32
+ cl_b2f_loop_32_finish:
+-        addlts  r2, #32
++        addslt  r2, #32
+         beq     conjoint_longs_finish
+         cmp     r2, #16
+         blt	cl_b2f_copy_8
+diff --git a/src/hotspot/os_cpu/linux_arm/os_linux_arm.cpp b/src/hotspot/os_cpu/linux_arm/os_linux_arm.cpp
+index 41a4dbea3..1b77c0cb9 100644
+--- a/src/hotspot/os_cpu/linux_arm/os_linux_arm.cpp
++++ b/src/hotspot/os_cpu/linux_arm/os_linux_arm.cpp
+@@ -70,7 +70,11 @@
+ # include <pwd.h>
+ # include <poll.h>
+ # include <ucontext.h>
++#ifndef __ANDROID__
+ # include <fpu_control.h>
++#else
++# include "fpu_control.h" //include the local header
++#endif
+ # include <asm/ptrace.h>
+ 
+ #define SPELL_REG_SP  "sp"
+@@ -88,8 +92,14 @@ enum {
+ #endif
+ 
+ address os::current_stack_pointer() {
++#if defined(__clang__) || defined(__llvm__)
++  void *sp;
++  __asm__("mov %0, " SPELL_REG_SP : "=r"(sp));
++  return (address) sp;
++#else
+   register address sp __asm__ (SPELL_REG_SP);
+   return sp;
++#endif
+ }
+ 
+ char* os::non_memory_address_word() {
+@@ -444,8 +454,8 @@ void os::setup_fpu() {
+ #if !defined(__SOFTFP__) && defined(__VFP_FP__)
+   // Turn on IEEE-754 compliant VFP mode
+   __asm__ volatile (
+-    "mov %%r0, #0;"
+-    "fmxr fpscr, %%r0"
++    "mov r0, #0;"
++    "fmxr fpscr, r0"
+     : /* no output */ : /* no input */ : "r0"
+   );
+ #endif
+diff --git a/src/hotspot/os_cpu/linux_x86/fpu_control.h b/src/hotspot/os_cpu/linux_x86/fpu_control.h
+new file mode 100644
+index 000000000..605302c09
+--- /dev/null
++++ b/src/hotspot/os_cpu/linux_x86/fpu_control.h
+@@ -0,0 +1,109 @@
++/* FPU control word bits.  x86 version.
++   Copyright (C) 1993-2012 Free Software Foundation, Inc.
++   This file is part of the GNU C Library.
++   Contributed by Olaf Flebbe.
++
++   The GNU C Library is free software; you can redistribute it and/or
++   modify it under the terms of the GNU Lesser General Public
++   License as published by the Free Software Foundation; either
++   version 2.1 of the License, or (at your option) any later version.
++
++   The GNU C Library is distributed in the hope that it will be useful,
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++   Lesser General Public License for more details.
++
++   You should have received a copy of the GNU Lesser General Public
++   License along with the GNU C Library; if not, see
++   <http://www.gnu.org/licenses/>.  */
++
++#ifndef _FPU_CONTROL_H
++#define _FPU_CONTROL_H	1
++
++/* Note that this file sets on x86-64 only the x87 FPU, it does not
++   touch the SSE unit.  */
++
++/* Here is the dirty part. Set up your 387 through the control word
++ * (cw) register.
++ *
++ *     15-13    12  11-10  9-8     7-6     5    4    3    2    1    0
++ * | reserved | IC | RC  | PC | reserved | PM | UM | OM | ZM | DM | IM
++ *
++ * IM: Invalid operation mask
++ * DM: Denormalized operand mask
++ * ZM: Zero-divide mask
++ * OM: Overflow mask
++ * UM: Underflow mask
++ * PM: Precision (inexact result) mask
++ *
++ * Mask bit is 1 means no interrupt.
++ *
++ * PC: Precision control
++ * 11 - round to extended precision
++ * 10 - round to double precision
++ * 00 - round to single precision
++ *
++ * RC: Rounding control
++ * 00 - rounding to nearest
++ * 01 - rounding down (toward - infinity)
++ * 10 - rounding up (toward + infinity)
++ * 11 - rounding toward zero
++ *
++ * IC: Infinity control
++ * That is for 8087 and 80287 only.
++ *
++ * The hardware default is 0x037f which we use.
++ */
++
++#include <features.h>
++
++/* masking of interrupts */
++#define _FPU_MASK_IM  0x01
++#define _FPU_MASK_DM  0x02
++#define _FPU_MASK_ZM  0x04
++#define _FPU_MASK_OM  0x08
++#define _FPU_MASK_UM  0x10
++#define _FPU_MASK_PM  0x20
++
++/* precision control */
++#define _FPU_EXTENDED 0x300	/* libm requires double extended precision.  */
++#define _FPU_DOUBLE   0x200
++#define _FPU_SINGLE   0x0
++
++/* rounding control */
++#define _FPU_RC_NEAREST 0x0    /* RECOMMENDED */
++#define _FPU_RC_DOWN    0x400
++#define _FPU_RC_UP      0x800
++#define _FPU_RC_ZERO    0xC00
++
++#define _FPU_RESERVED 0xF0C0  /* Reserved bits in cw */
++
++
++/* The fdlibm code requires strict IEEE double precision arithmetic,
++   and no interrupts for exceptions, rounding to nearest.  */
++
++#define _FPU_DEFAULT  0x037f
++
++/* IEEE:  same as above.  */
++#define _FPU_IEEE     0x037f
++
++/* Type of the control word.  */
++typedef unsigned int fpu_control_t __attribute__ ((__mode__ (__HI__)));
++
++/* Macros for accessing the hardware control word.  "*&" is used to
++   work around a bug in older versions of GCC.  __volatile__ is used
++   to support combination of writing the control register and reading
++   it back.  Without __volatile__, the old value may be used for reading
++   back under compiler optimization.
++
++   Note that the use of these macros is not sufficient anymore with
++   recent hardware nor on x86-64.  Some floating point operations are
++   executed in the SSE/SSE2 engines which have their own control and
++   status register.  */
++#define _FPU_GETCW(cw) __asm__ __volatile__ ("fnstcw %0" : "=m" (*&cw))
++#define _FPU_SETCW(cw) __asm__ __volatile__ ("fldcw %0" : : "m" (*&cw))
++
++/* Default control word set at startup.  */
++extern fpu_control_t __fpu_control;
++
++#endif	/* fpu_control.h */
+diff --git a/src/hotspot/share/utilities/compilerWarnings.hpp b/src/hotspot/share/utilities/compilerWarnings.hpp
+index 3a2a94164..48ca109c6 100644
+--- a/src/hotspot/share/utilities/compilerWarnings.hpp
++++ b/src/hotspot/share/utilities/compilerWarnings.hpp
+@@ -128,7 +128,12 @@
+ 
+ // Both Linux and AIX C libraries declare functions noexcept.
+ // Neither BSD nor Windows C libraries declare functions noexcept.
++#ifdef __ANDROID__
++// Android bionic headers do not declare C library functions noexcept.
++#define FORBIDDEN_FUNCTION_COND_NOEXCEPT_noexcept
++#else
+ #define FORBIDDEN_FUNCTION_COND_NOEXCEPT_noexcept NOT_WINDOWS(NOT_BSD(noexcept))
++#endif
+ #define FORBIDDEN_FUNCTION_COND_NOEXCEPT_
+ 
+ #ifndef FORBIDDEN_FUNCTION_IMPORT_SPEC
+diff --git a/src/hotspot/share/utilities/elfFile.hpp b/src/hotspot/share/utilities/elfFile.hpp
+index 0bfa821e2..76054d6fc 100644
+--- a/src/hotspot/share/utilities/elfFile.hpp
++++ b/src/hotspot/share/utilities/elfFile.hpp
+@@ -47,8 +47,10 @@ typedef Elf64_Phdr      Elf_Phdr;
+ typedef Elf64_Sym       Elf_Sym;
+ 
+ #if !defined(_ALLBSD_SOURCE) || defined(__APPLE__)
++#ifndef ELF_ST_TYPE
+ #define ELF_ST_TYPE ELF64_ST_TYPE
+ #endif
++#endif
+ 
+ #else
+ 
+@@ -62,7 +64,7 @@ typedef Elf32_Shdr      Elf_Shdr;
+ typedef Elf32_Phdr      Elf_Phdr;
+ typedef Elf32_Sym       Elf_Sym;
+ 
+-#if !defined(_ALLBSD_SOURCE) || defined(__APPLE__)
++#if (!defined(_ALLBSD_SOURCE) || defined(__APPLE__)) && !defined(ELF_ST_TYPE)
+ #define ELF_ST_TYPE ELF32_ST_TYPE
+ #endif
+ #endif
+diff --git a/src/hotspot/share/utilities/globalDefinitions_gcc.hpp b/src/hotspot/share/utilities/globalDefinitions_gcc.hpp
+index 302a62de6..2a07806e4 100644
+--- a/src/hotspot/share/utilities/globalDefinitions_gcc.hpp
++++ b/src/hotspot/share/utilities/globalDefinitions_gcc.hpp
+@@ -50,6 +50,10 @@
+ #include <time.h>
+ #include <wchar.h>
+ 
++#if defined(__ANDROID__) && !defined(ANDROID)
++#define ANDROID 1
++#endif
++
+ #if defined(LINUX) || defined(_ALLBSD_SOURCE) || defined(_AIX)
+ #include <signal.h>
+ #ifndef __OpenBSD__
+diff --git a/src/java.base/share/native/libtinyiconv/iconv.cpp b/src/java.base/share/native/libtinyiconv/iconv.cpp
+new file mode 100644
+index 000000000..7018b6ce2
+--- /dev/null
++++ b/src/java.base/share/native/libtinyiconv/iconv.cpp
+@@ -0,0 +1,438 @@
++/*
++ * Copyright (C) 2017 The Android Open Source Project
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ *  * Redistributions of source code must retain the above copyright
++ *    notice, this list of conditions and the following disclaimer.
++ *  * Redistributions in binary form must reproduce the above copyright
++ *    notice, this list of conditions and the following disclaimer in
++ *    the documentation and/or other materials provided with the
++ *    distribution.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
++ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
++ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
++ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
++ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
++ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
++ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
++ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
++ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
++ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
++ * SUCH DAMAGE.
++ */
++
++#ifdef __ANDROID__
++
++#include <ctype.h>
++#include <endian.h>
++#include <errno.h>
++#include <iconv.h>
++#include <stdbool.h>
++#include <stdint.h>
++#include <stdlib.h>
++#include <string.h>
++#include <uchar.h>
++#include <wchar.h>
++
++__BEGIN_DECLS
++
++/*
++ * These return values are specified by POSIX for multibyte conversion
++ * functions.
++ */
++
++#ifdef __cplusplus
++#define __MB_ERR_ILLEGAL_SEQUENCE static_cast<size_t>(-1)
++#define __MB_ERR_INCOMPLETE_SEQUENCE static_cast<size_t>(-2)
++#else
++#define __MB_ERR_ILLEGAL_SEQUENCE (size_t)(-1)
++#define __MB_ERR_INCOMPLETE_SEQUENCE (size_t)(-2)
++#endif // __cplusplus
++#define __MB_IS_ERR(rv) (rv == __MB_ERR_ILLEGAL_SEQUENCE || \
++                         rv == __MB_ERR_INCOMPLETE_SEQUENCE)
++static inline __wur size_t mbstate_bytes_so_far(const mbstate_t* ps) {
++  return
++      (ps->__seq[2] != 0) ? 3 :
++      (ps->__seq[1] != 0) ? 2 :
++      (ps->__seq[0] != 0) ? 1 : 0;
++}
++static inline void mbstate_set_byte(mbstate_t* ps, int i, char byte) {
++  ps->__seq[i] = (uint8_t)(byte);
++}
++static inline __wur uint8_t mbstate_get_byte(const mbstate_t* ps, int n) {
++  return ps->__seq[n];
++}
++static inline __wur size_t mbstate_reset_and_return_illegal(int _errno, mbstate_t* ps) {
++  errno = _errno;
++#ifdef __cplusplus
++  *(reinterpret_cast<uint32_t*>(ps->__seq)) = 0;
++#else
++  *(uint32_t*)(ps->__seq) = 0;
++#endif // __cplusplus
++  return __MB_ERR_ILLEGAL_SEQUENCE;
++}
++static inline __wur size_t mbstate_reset_and_return(int _return, mbstate_t* ps) {
++#ifdef __cplusplus
++  *(reinterpret_cast<uint32_t*>(ps->__seq)) = 0;
++#else
++  *(uint32_t*)(ps->__seq) = 0;
++#endif // __cplusplus
++  return _return;
++}
++
++#ifdef __cplusplus
++# define INVALID_ICONV_T reinterpret_cast<iconv_t>(-1)
++#else // !__cplusplus
++# define INVALID_ICONV_T (iconv_t)(-1)
++#endif // __cplusplus
++
++// Ideally we'd use icu4c but the API mismatch seems too great. So we just offer something
++// equivalent to (but slightly easier to use for runs of text than) <uchar.h>. If you're
++// here to add more encodings, consider working on finishing the icu4c NDK wrappers instead.
++
++#ifdef __cplusplus
++ enum Encoding
++#else
++ typedef enum
++#endif // __cplusplus
++{
++  US_ASCII,
++  UTF_8,
++  UTF_16_LE,
++  UTF_16_BE,
++  UTF_32_LE,
++  UTF_32_BE,
++  WCHAR_T,
++#ifdef __cplusplus
++ };
++#else
++ } Encoding;
++#endif // __cplusplus
++
++#ifdef __cplusplus
++ enum Mode
++#else
++ typedef enum
++#endif // __cplusplus
++{
++  ERROR,
++  IGNORE,
++  TRANSLIT,
++#ifdef __cplusplus
++ };
++#else
++ } Mode;
++#endif // __cplusplus
++
++// This matching is strange but true.
++// See http://www.unicode.org/reports/tr22/#Charset_Alias_Matching.
++static bool __match_encoding(const char* lhs, const char* rhs) {
++  while (*lhs && *rhs) {
++    // Skip non-alnum in lhs; "UTF-8", "UTF_8", "UTF8", "UTF 8" are all equivalent.
++    // Also implement the "delete each 0 that is not preceded by a digit" rule.
++    for (; *lhs; ++lhs) {
++      if (isalnum(*lhs) && (*lhs != '0' || !isdigit(*(lhs + 1)))) break;
++    }
++    // Case doesn't matter either.
++    if (tolower(*lhs) != tolower(*rhs)) break;
++    ++lhs;
++    ++rhs;
++  }
++  // As a special case we treat the GNU "//" extensions as end of string.
++  if ((*lhs == '\0' || strstr(lhs, "//") == lhs) && *rhs == '\0') return true;
++  return false;
++}
++
++static bool __parse_encoding(const char* s, Encoding* encoding, Mode* mode) {
++  const char* suffix = strstr(s, "//");
++  if (suffix) {
++    if (!mode) return false;
++    if (strcmp(suffix, "//IGNORE") == 0) {
++      *mode = IGNORE;
++    } else if (strcmp(suffix, "//TRANSLIT") == 0) {
++      *mode = TRANSLIT;
++    } else {
++      return false;
++    }
++  }
++  if (__match_encoding(s, "utf8")) {
++    *encoding = UTF_8;
++  } else if (__match_encoding(s, "ascii") || __match_encoding(s, "usascii")) {
++    *encoding = US_ASCII;
++  } else if (__match_encoding(s, "utf16le")) {
++    *encoding = UTF_16_LE;
++  } else if (__match_encoding(s, "utf16be")) {
++    *encoding = UTF_16_BE;
++  } else if (__match_encoding(s, "utf32le")) {
++    *encoding = UTF_32_LE;
++  } else if (__match_encoding(s, "utf32be")) {
++    *encoding = UTF_32_BE;
++  } else if (__match_encoding(s, "wchart")) {
++    *encoding = WCHAR_T;
++  } else {
++    return false;
++  }
++  return true;
++}
++
++struct __iconv_t {
++  Encoding src_encoding;
++  Encoding dst_encoding;
++  Mode mode;
++/*
++  __iconv_t() : mode(ERROR) {
++  }
++*/
++  int Convert(char** src_buf0, size_t* src_bytes_left0, char** dst_buf0, size_t* dst_bytes_left0) {
++    // Reset state.
++    wc = 0;
++    memset(&ps, 0, sizeof(ps));
++    replacement_count = 0;
++    ignored = false;
++    src_buf = src_buf0;
++    src_bytes_left = src_bytes_left0;
++    dst_buf = dst_buf0;
++    dst_bytes_left = dst_bytes_left0;
++    while (*src_bytes_left > 0) {
++      if (!GetNext() || !Convert()) return -1;
++    }
++    return Done();
++  }
++ private:
++  char32_t wc;
++  char buf[16];
++  size_t src_bytes_used;
++  size_t dst_bytes_used;
++  mbstate_t ps;
++  size_t replacement_count;
++  bool ignored;
++  char** src_buf;
++  size_t* src_bytes_left;
++  char** dst_buf;
++  size_t* dst_bytes_left;
++  bool GetNext() {
++    errno = 0;
++    switch (src_encoding) {
++      case US_ASCII:
++        wc = **src_buf;
++        src_bytes_used = 1;
++        if (wc > 0x7f) errno = EILSEQ;
++        break;
++      case UTF_8:
++        src_bytes_used = mbrtoc32(&wc, *src_buf, *src_bytes_left, &ps);
++        if (src_bytes_used == __MB_ERR_ILLEGAL_SEQUENCE) {
++          break;  // EILSEQ already set.
++        } else if (src_bytes_used == __MB_ERR_INCOMPLETE_SEQUENCE) {
++          errno = EINVAL;
++          return false;
++        }
++        break;
++      case UTF_16_BE:
++      case UTF_16_LE: {
++        if (*src_bytes_left < 2) {
++          errno = EINVAL;
++          return false;
++        }
++        bool swap = (src_encoding == UTF_16_BE);
++        wc = In16(*src_buf, swap);
++        // 0xd800-0xdbff: high surrogates
++        // 0xdc00-0xdfff: low surrogates
++        if (wc >= 0xd800 && wc <= 0xdfff) {
++          if (wc >= 0xdc00) {  // Low surrogate before high surrogate.
++            errno = EILSEQ;
++            return false;
++          }
++          if (*src_bytes_left < 4) {
++            errno = EINVAL;
++            return false;
++          }
++          uint16_t hi = wc;
++          uint16_t lo = In16(*src_buf + 2, swap);
++          wc = 0x10000 + ((hi - 0xd800) << 10) + (lo - 0xdc00);
++          src_bytes_used = 4;
++        }
++        break;
++      }
++      case UTF_32_BE:
++      case UTF_32_LE:
++      case WCHAR_T:
++        if (*src_bytes_left < 4) {
++          errno = EINVAL;
++          return false;
++        }
++        wc = In32(*src_buf, (src_encoding == UTF_32_BE));
++        break;
++    }
++    if (errno == EILSEQ) {
++      switch (mode) {
++        case ERROR:
++          return false;
++        case IGNORE:
++          *src_buf += src_bytes_used;
++          *src_bytes_left -= src_bytes_used;
++          ignored = true;
++          return GetNext();
++        case TRANSLIT:
++          wc = '?';
++          ++replacement_count;
++          return true;
++      }
++    }
++    return true;
++  }
++
++  bool Convert() {
++    errno = 0;
++    switch (dst_encoding) {
++      case US_ASCII:
++        buf[0] = wc;
++        dst_bytes_used = 1;
++        if (wc > 0x7f) errno = EILSEQ;
++        break;
++      case UTF_8:
++        dst_bytes_used = c32rtomb(buf, wc, &ps);
++        if (dst_bytes_used == __MB_ERR_ILLEGAL_SEQUENCE) {
++          break;  // EILSEQ already set.
++        } else if (dst_bytes_used == __MB_ERR_INCOMPLETE_SEQUENCE) {
++          errno = EINVAL;
++          return false;
++        }
++        break;
++      case UTF_16_BE:
++      case UTF_16_LE: {
++        bool swap = (dst_encoding == UTF_16_BE);
++        if (wc < 0x10000) {  // BMP.
++          Out16(buf, wc, swap);
++        } else {  // Supplementary plane; output surrogate pair.
++          wc -= 0x10000;
++          char16_t hi = 0xd800 | (wc >> 10);
++          char16_t lo = 0xdc00 | (wc & 0x3ff);
++          Out16(buf + 0, hi, swap);
++          Out16(buf + 2, lo, swap);
++          dst_bytes_used = 4;
++        }
++      } break;
++      case UTF_32_BE:
++      case UTF_32_LE:
++      case WCHAR_T:
++        Out32(wc, (dst_encoding == UTF_32_BE));
++        break;
++    }
++    if (errno == EILSEQ) {
++      if (mode == IGNORE) {
++        *src_buf += src_bytes_used;
++        *src_bytes_left -= src_bytes_used;
++        ignored = true;
++        return true;
++      } else if (mode == TRANSLIT) {
++        wc = '?';
++        ++replacement_count;
++        return Convert();
++      }
++      return false;
++    }
++    return Emit();
++  }
++
++  uint16_t In16(const char* buf, bool swap) {
++#ifdef __cplusplus
++    const uint8_t* src = reinterpret_cast<const uint8_t*>(buf);
++#else // !__cplusplus
++    const uint8_t* src = (const uint8_t*)(buf);
++#endif // __cplusplus
++    uint16_t wc = (src[0]) | (src[1] << 8);
++    if (swap) wc = __swap16(wc);
++    src_bytes_used = 2;
++    return wc;
++  }
++
++  uint32_t In32(const char* buf, bool swap) {
++#ifdef __cplusplus
++    const uint8_t* src = reinterpret_cast<const uint8_t*>(buf);
++#else // !__cplusplus
++    const uint8_t* src = (const uint8_t*)(buf);
++#endif // __cplusplus
++    uint32_t wc = (src[0]) | (src[1] << 8) | (src[2] << 16) | (src[3] << 24);
++    if (swap) wc = __swap32(wc);
++    src_bytes_used = 4;
++    return wc;
++  }
++
++  void Out16(char* dst, char16_t ch, bool swap) {
++    if (swap) ch = __swap16(ch);
++    dst[0] = ch;
++    dst[1] = ch >> 8;
++    dst_bytes_used = 2;
++  }
++
++  void Out32(char32_t ch, bool swap) {
++    if (swap) ch = __swap32(ch);
++    buf[0] = ch;
++    buf[1] = ch >> 8;
++    buf[2] = ch >> 16;
++    buf[3] = ch >> 24;
++    dst_bytes_used = 4;
++  }
++
++  bool Emit() {
++    if (dst_bytes_used > *dst_bytes_left) {
++      errno = E2BIG;
++      return false;
++    }
++    memcpy(*dst_buf, buf, dst_bytes_used);
++    *src_buf += src_bytes_used;
++    *src_bytes_left -= src_bytes_used;
++    *dst_buf += dst_bytes_used;
++    *dst_bytes_left -= dst_bytes_used;
++    return true;
++  }
++
++  int Done() {
++    if (mode == TRANSLIT) return replacement_count;
++    if (ignored) {
++      errno = EILSEQ;
++      return -1;
++    }
++    return 0;
++  }
++};
++
++iconv_t iconv_open(const char* __dst_encoding, const char* __src_encoding) {
++  iconv_t result = iconv_t();
++  result->mode = ERROR;
++  if (!__parse_encoding(__src_encoding, &result->src_encoding, 0 /* nullptr */) ||
++      !__parse_encoding(__dst_encoding, &result->dst_encoding, &result->mode)) {
++    free(result);
++    errno = EINVAL;
++    return INVALID_ICONV_T;
++  }
++  return result;
++}
++
++size_t iconv(iconv_t __converter,
++             char** __src_buf, size_t* __src_bytes_left,
++             char** __dst_buf, size_t* __dst_bytes_left) {
++  if (__converter == INVALID_ICONV_T) {
++    errno = EBADF;
++    return -1;
++  }
++  return __converter->Convert(__src_buf, __src_bytes_left, __dst_buf, __dst_bytes_left);
++}
++
++int iconv_close(iconv_t __converter) {
++  if (__converter == INVALID_ICONV_T) {
++    errno = EBADF;
++    return -1;
++  }
++  free(__converter);
++  return 0;
++}
++
++__END_DECLS
++
++#endif // __ANDROID__
+diff --git a/src/java.base/unix/classes/sun/net/dns/ResolverConfigurationImpl.java b/src/java.base/unix/classes/sun/net/dns/ResolverConfigurationImpl.java
+index 2f633ad71..513c70f8b 100644
+--- a/src/java.base/unix/classes/sun/net/dns/ResolverConfigurationImpl.java
++++ b/src/java.base/unix/classes/sun/net/dns/ResolverConfigurationImpl.java
+@@ -63,8 +63,9 @@ private ArrayList<String> resolvconf(String keyword,
+         ArrayList<String> ll = new ArrayList<>();
+ 
+         try {
++            String resolvPath = System.getProperty("ext.net.resolvPath", "/etc/resolv.conf");
+             BufferedReader in =
+-                new BufferedReader(new FileReader("/etc/resolv.conf"));
++                new BufferedReader(new FileReader(resolvPath));
+             String line;
+             while ((line = in.readLine()) != null) {
+                 int maxvalues = maxperkeyword;
+diff --git a/src/java.base/unix/native/libjava/ProcessImpl_md.c b/src/java.base/unix/native/libjava/ProcessImpl_md.c
+index 69af948d2..1a5aaa39c 100644
+--- a/src/java.base/unix/native/libjava/ProcessImpl_md.c
++++ b/src/java.base/unix/native/libjava/ProcessImpl_md.c
+@@ -580,6 +580,9 @@ spawnChild(JNIEnv *env, jobject process, ChildStuff *c, const char *helperpath)
+     c->redirectErrorStream = false;
+ 
+     rval = posix_spawn(&resultPid, helperpath, &file_actions, 0, (char * const *) hlpargs, environ);
++#ifdef __ANDROID__
++    posix_spawn_file_actions_destroy(&file_actions);
++#endif
+ 
+     if (rval != 0) {
+         return -1;
+diff --git a/src/java.base/unix/native/libjava/java_props_md.c b/src/java.base/unix/native/libjava/java_props_md.c
+index 1cbc3665e..de6b4bfca 100644
+--- a/src/java.base/unix/native/libjava/java_props_md.c
++++ b/src/java.base/unix/native/libjava/java_props_md.c
+@@ -46,6 +46,100 @@
+ #include "java_props_macosx.h"
+ #endif
+ 
++#ifdef __ANDROID__
++// From https://android.googlesource.com/platform/bionic/+/master/libc/bionic/langinfo.cpp
++/*
++ * Copyright (C) 2016 The Android Open Source Project
++ * All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ *  * Redistributions of source code must retain the above copyright
++ *    notice, this list of conditions and the following disclaimer.
++ *  * Redistributions in binary form must reproduce the above copyright
++ *    notice, this list of conditions and the following disclaimer in
++ *    the documentation and/or other materials provided with the
++ *    distribution.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
++ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
++ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
++ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
++ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
++ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
++ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
++ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
++ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
++ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
++ * SUCH DAMAGE.
++ */
++
++char* nl_langinfo(nl_item item) {
++  const char* result = "";
++  switch (item) {
++    case CODESET: result = (MB_CUR_MAX == 1) ? "ASCII" : "UTF-8"; break;
++    case D_T_FMT: result = "%F %T %z"; break;
++    case D_FMT: result = "%F"; break;
++    case T_FMT: result = "%T"; break;
++    case T_FMT_AMPM: result = "%I:%M:%S %p"; break;
++    case AM_STR: result = "AM"; break;
++    case PM_STR: result = "PM"; break;
++    case DAY_1: result = "Sunday"; break;
++    case DAY_2: result = "Monday"; break;
++    case DAY_3: result = "Tuesday"; break;
++    case DAY_4: result = "Wednesday"; break;
++    case DAY_5: result = "Thursday"; break;
++    case DAY_6: result = "Friday"; break;
++    case DAY_7: result = "Saturday"; break;
++    case ABDAY_1: result = "Sun"; break;
++    case ABDAY_2: result = "Mon"; break;
++    case ABDAY_3: result = "Tue"; break;
++    case ABDAY_4: result = "Wed"; break;
++    case ABDAY_5: result = "Thu"; break;
++    case ABDAY_6: result = "Fri"; break;
++    case ABDAY_7: result = "Sat"; break;
++    case MON_1: result = "January"; break;
++    case MON_2: result = "February"; break;
++    case MON_3: result = "March"; break;
++    case MON_4: result = "April"; break;
++    case MON_5: result = "May"; break;
++    case MON_6: result = "June"; break;
++    case MON_7: result = "July"; break;
++    case MON_8: result = "August"; break;
++    case MON_9: result = "September"; break;
++    case MON_10: result = "October"; break;
++    case MON_11: result = "November"; break;
++    case MON_12: result = "December"; break;
++    case ABMON_1: result = "Jan"; break;
++    case ABMON_2: result = "Feb"; break;
++    case ABMON_3: result = "Mar"; break;
++    case ABMON_4: result = "Apr"; break;
++    case ABMON_5: result = "May"; break;
++    case ABMON_6: result = "Jun"; break;
++    case ABMON_7: result = "Jul"; break;
++    case ABMON_8: result = "Aug"; break;
++    case ABMON_9: result = "Sep"; break;
++    case ABMON_10: result = "Oct"; break;
++    case ABMON_11: result = "Nov"; break;
++    case ABMON_12: result = "Dec"; break;
++    case ERA: result = ""; break;
++    case ERA_D_FMT: result = ""; break;
++    case ERA_D_T_FMT: result = ""; break;
++    case ERA_T_FMT: result = ""; break;
++    case ALT_DIGITS: result = ""; break;
++    case RADIXCHAR: result = "."; break;
++    case THOUSEP: result = ""; break;
++    case YESEXPR: result = "^[yY]"; break;
++    case NOEXPR: result = "^[nN]"; break;
++    case CRNCYSTR: result = ""; break;
++    default: break;
++  }
++  return (char*) result;
++}
++#endif
++
+ #if defined(_ALLBSD_SOURCE)
+ #if !defined(P_tmpdir)
+ #include <paths.h>
+diff --git a/src/java.base/unix/native/libjava/jni_util_md.c b/src/java.base/unix/native/libjava/jni_util_md.c
+index 7195b3def..460174f9d 100644
+--- a/src/java.base/unix/native/libjava/jni_util_md.c
++++ b/src/java.base/unix/native/libjava/jni_util_md.c
+@@ -31,7 +31,7 @@
+ #include "jni_util.h"
+ #include "dlfcn.h"
+ 
+-#if defined(LINUX) && (defined(_GNU_SOURCE) || \
++#if !defined(__ANDROID__) && defined(LINUX) && (defined(_GNU_SOURCE) || \
+          (defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE < 200112L \
+              && defined(_XOPEN_SOURCE) && _XOPEN_SOURCE < 600))
+ extern int __xpg_strerror_r(int, char *, size_t);
+diff --git a/src/java.base/unix/native/libjava/posix_spawn.c b/src/java.base/unix/native/libjava/posix_spawn.c
+new file mode 100644
+index 000000000..90936c584
+--- /dev/null
++++ b/src/java.base/unix/native/libjava/posix_spawn.c
+@@ -0,0 +1,197 @@
++// From https://android.googlesource.com/platform/external/dhcpcd-6.8.2/+/refs/heads/pie-dr1-release/compat/posix_spawn.c
++/*
++ * dhcpcd - DHCP client daemon
++ * Copyright (c) 2006-2012 Roy Marples <roy@marples.name>
++ * All rights reserved
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ *    notice, this list of conditions and the following disclaimer.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ *    notice, this list of conditions and the following disclaimer in the
++ *    documentation and/or other materials provided with the distribution.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
++ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
++ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
++ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
++ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
++ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
++ * SUCH DAMAGE.
++ */
++
++/* This implementation of posix_spawn is only suitable for the needs of dhcpcd
++ * but it could easily be extended to other applications. */
++
++#include <sys/types.h>
++#include <sys/wait.h>
++#include <errno.h>
++#include <fcntl.h>
++#include <signal.h>
++#include <stdlib.h>
++#include <string.h>
++#include <unistd.h>
++
++#include "posix_spawn.h"
++
++#ifndef _NSIG
++#ifdef _SIG_MAXSIG
++#define _NSIG _SIG_MAXSIG + 1
++#else
++/* Guess */
++#define _NSIG SIGPWR + 1
++#endif
++#endif
++
++extern char **environ;
++
++static int
++posix_spawnattr_handle(const posix_spawnattr_t *attrp)
++{
++  struct sigaction sa;
++  int i;
++  if (attrp->posix_attr_flags & POSIX_SPAWN_SETSIGMASK)
++    sigprocmask(SIG_SETMASK, &attrp->posix_attr_sigmask, NULL);
++  if (attrp->posix_attr_flags & POSIX_SPAWN_SETSIGDEF) {
++    memset(&sa, 0, sizeof(sa));
++    sa.sa_handler = SIG_DFL;
++    for (i = 1; i < _NSIG; i++) {
++      if (sigismember(&attrp->posix_attr_sigdefault, i)) {
++        if (sigaction(i, &sa, NULL) == -1)
++          return -1;
++      }
++    }
++  }
++  return 0;
++}
++
++inline static int
++is_vfork_safe(short int flags)
++{
++  return !(flags & (POSIX_SPAWN_SETSIGDEF | POSIX_SPAWN_SETSIGMASK));
++}
++
++int
++posix_spawn(pid_t *pid, const char *path,
++  const posix_spawn_file_actions_t *file_actions,
++  const posix_spawnattr_t *attrp,
++  char *const argv[], char *const envp[])
++{
++  short int flags;
++  pid_t p;
++  volatile int error;
++  error = 0;
++  flags = attrp ? attrp->posix_attr_flags : 0;
++  /* dup2 file actions only touch the fd table, so they are vfork safe. */
++  if (is_vfork_safe(flags))
++    p = vfork();
++  else
++#ifdef THERE_IS_NO_FORK
++    return ENOSYS;
++#else
++    p = fork();
++#endif
++  switch (p) {
++  case -1:
++    return errno;
++  case 0:
++    if (attrp) {
++      error = posix_spawnattr_handle(attrp);
++      if (error)
++        _exit(127);
++    }
++    if (file_actions != NULL && *file_actions != NULL) {
++      const struct __posix_spawn_file_actions *fa = *file_actions;
++      int i;
++      for (i = 0; i < fa->count; i++) {
++        int from = fa->dup2_from[i], to = fa->dup2_to[i];
++        if (from == to) {
++          /* POSIX: dup2 action with identical fds clears FD_CLOEXEC */
++          int fl = fcntl(from, F_GETFD);
++          if (fl == -1 || fcntl(from, F_SETFD, fl & ~FD_CLOEXEC) == -1) {
++            error = errno;
++            _exit(127);
++          }
++        } else if (dup2(from, to) == -1) {
++          error = errno;
++          _exit(127);
++        }
++      }
++    }
++    execve(path, argv, envp);
++    error = errno;
++    _exit(127);
++  default:
++    if (error != 0)
++      waitpid(p, NULL, WNOHANG);
++    else if (pid != NULL)
++      *pid = p;
++    return error;
++  }
++}
++
++int
++posix_spawnattr_init(posix_spawnattr_t *attr)
++{
++  memset(attr, 0, sizeof(*attr));
++  attr->posix_attr_flags = 0;
++  sigprocmask(0, NULL, &attr->posix_attr_sigmask);
++  sigemptyset(&attr->posix_attr_sigdefault);
++  return 0;
++}
++
++int
++posix_spawnattr_setflags(posix_spawnattr_t *attr, short flags)
++{
++  attr->posix_attr_flags = flags;
++  return 0;
++}
++
++int
++posix_spawnattr_setsigmask(posix_spawnattr_t *attr, const sigset_t *sigmask)
++{
++  attr->posix_attr_sigmask = *sigmask;
++  return 0;
++}
++
++int
++posix_spawnattr_setsigdefault(posix_spawnattr_t *attr, const sigset_t *sigmask)
++{
++  attr->posix_attr_sigdefault = *sigmask;
++  return 0;
++}
++
++int
++posix_spawn_file_actions_init(posix_spawn_file_actions_t *fa)
++{
++  *fa = (struct __posix_spawn_file_actions *) calloc(1, sizeof(struct __posix_spawn_file_actions));
++  return *fa == NULL ? ENOMEM : 0;
++}
++
++int
++posix_spawn_file_actions_destroy(posix_spawn_file_actions_t *fa)
++{
++  free(*fa);
++  *fa = NULL;
++  return 0;
++}
++
++int
++posix_spawn_file_actions_adddup2(posix_spawn_file_actions_t *fa, int from, int to)
++{
++  if (from < 0 || to < 0)
++    return EBADF;
++  if (*fa == NULL)
++    return EINVAL;
++  if ((*fa)->count >= COMPAT_SPAWN_MAX_ACTIONS)
++    return ENOMEM;
++  (*fa)->dup2_from[(*fa)->count] = from;
++  (*fa)->dup2_to[(*fa)->count] = to;
++  (*fa)->count++;
++  return 0;
++}
+diff --git a/src/java.base/unix/native/libjava/posix_spawn.h b/src/java.base/unix/native/libjava/posix_spawn.h
+new file mode 100644
+index 000000000..a75c400b1
+--- /dev/null
++++ b/src/java.base/unix/native/libjava/posix_spawn.h
+@@ -0,0 +1,62 @@
++// From https://android.googlesource.com/platform/external/dhcpcd-6.8.2/+/refs/heads/pie-dr1-release/compat/posix_spawn.h
++/*
++ * dhcpcd - DHCP client daemon
++ * Copyright (c) 2006-2012 Roy Marples <roy@marples.name>
++ * All rights reserved
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ *    notice, this list of conditions and the following disclaimer.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ *    notice, this list of conditions and the following disclaimer in the
++ *    documentation and/or other materials provided with the distribution.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
++ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
++ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
++ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
++ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
++ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
++ * SUCH DAMAGE.
++ */
++
++#ifndef POSIX_SPAWN_H
++#define POSIX_SPAWN_H
++
++#include <signal.h>
++
++typedef struct {
++    short posix_attr_flags;
++#define POSIX_SPAWN_SETSIGDEF       0x10
++#define POSIX_SPAWN_SETSIGMASK      0x20
++    sigset_t posix_attr_sigmask;
++    sigset_t posix_attr_sigdefault;
++} posix_spawnattr_t;
++
++/* Binary compatible with bionic's opaque pointer type (spawn.h). Only dup2
++ * actions are supported, which is all ProcessImpl_md.c (JDK 27+) needs. */
++#define COMPAT_SPAWN_MAX_ACTIONS 32
++struct __posix_spawn_file_actions {
++  int count;
++  int dup2_from[COMPAT_SPAWN_MAX_ACTIONS];
++  int dup2_to[COMPAT_SPAWN_MAX_ACTIONS];
++};
++typedef struct __posix_spawn_file_actions* posix_spawn_file_actions_t;
++int posix_spawn_file_actions_init(posix_spawn_file_actions_t *);
++int posix_spawn_file_actions_destroy(posix_spawn_file_actions_t *);
++int posix_spawn_file_actions_adddup2(posix_spawn_file_actions_t *, int, int);
++
++int posix_spawn(pid_t *, const char *,
++    const posix_spawn_file_actions_t *, const posix_spawnattr_t *,
++    char *const [], char *const []);
++int posix_spawnattr_init(posix_spawnattr_t *);
++int posix_spawnattr_setflags(posix_spawnattr_t *, short);
++int posix_spawnattr_setsigmask(posix_spawnattr_t *, const sigset_t *);
++int posix_spawnattr_setsigdefault(posix_spawnattr_t *, const sigset_t *);
++
++#endif
+diff --git a/src/java.base/unix/native/libjli/java_md.c b/src/java.base/unix/native/libjli/java_md.c
+index a75795af5..651a179ac 100644
+--- a/src/java.base/unix/native/libjli/java_md.c
++++ b/src/java.base/unix/native/libjli/java_md.c
+@@ -576,7 +576,58 @@ const char*
+ SetExecname(char **argv)
+ {
+     char* exec_path = NULL;
+-#if defined(__linux__)
++#if defined(__ANDROID__) //Since both __ANDROID__ and __linux__ are defined, we must let the preprocessor preprocess the __ANDRIOD__ part first
++    char *__java_home = getenv("JAVA_HOME");
++    // From http://hg.openjdk.java.net/mobile/jdk9/jdk/file/17bb8a98d5e3/src/java.base/unix/native/libjli/java_md_solinux.c#l844
++        /* For Android, 'self' would point to /system/bin/app_process
++         * since we are really executing a Dalvik program at this point.
++         * argv[0] points to the Dalvik application name and we set the
++         * path to __java_home.
++         */
++        char buf[PATH_MAX+1];
++        char *p = NULL;
++        if ((p = JLI_StrRChr(argv[0], '/')) != 0) {
++          /* may be running from command line */
++          p++;
++          if ((JLI_StrLen(p) == 4) && JLI_StrCmp(p, "java") == 0) {
++            /* started as 'java'. Must be command line */
++            JLI_TraceLauncher("SetExecName maybe command line = %s\n", argv[0]);
++            if (*argv[0] != '/') {
++              char *curdir = NULL;
++              /* get absolute path */
++              getcwd(buf, PATH_MAX);
++              curdir = JLI_StringDup(buf);
++              JLI_Snprintf(buf, PATH_MAX, "%s/%s", curdir, argv[0]);
++              JLI_MemFree(curdir);
++            } else {
++              JLI_Snprintf(buf, PATH_MAX, "%s", argv[0]);
++            }
++          } else {
++            /* Not command line, see if __java_home set */
++            if (__java_home != NULL) {
++              JLI_TraceLauncher("SetExecName not java = %s\n", __java_home);
++              JLI_Snprintf(buf, PATH_MAX, "%s/bin/java", __java_home);
++            } else {
++              /* Fake it as best we can or should we punt? */
++              JLI_TraceLauncher("SetExecName fake it = %s\n", argv[0]);
++              JLI_Snprintf(buf, PATH_MAX, "/data/data/%s/storage/jvm/bin/java",
++                           argv[0]);
++            }
++          }
++        } else {
++            /* Not started as 'java', see if __java_home set */
++            if (__java_home != NULL) {
++              JLI_TraceLauncher("SetExecName not command line = %s\n", __java_home);
++              JLI_Snprintf(buf, PATH_MAX, "%s/bin/java", __java_home);
++            } else {
++              /* Fake it as best we can or should we punt? */
++              JLI_TraceLauncher("SetExecName fake it 2 = %s\n", argv[0]);
++              JLI_Snprintf(buf, PATH_MAX, "/data/data/%s/storage/jvm/bin/java",
++                           argv[0]);
++            }
++        }
++        exec_path = JLI_StringDup(buf);
++#elif defined(__linux__)
+     {
+         const char* self = "/proc/self/exe";
+         char buf[PATH_MAX+1];
+@@ -586,10 +637,6 @@ SetExecname(char **argv)
+             exec_path = JLI_StringDup(buf);
+         }
+     }
+-#else /* !__linux__ */
+-    {
+-        /* Not implemented */
+-    }
+ #endif
+ 
+     if (exec_path == NULL) {
+diff --git a/src/java.base/unix/native/libnet/net_util_md.h b/src/java.base/unix/native/libnet/net_util_md.h
+index 639cf0051..b9fa162ff 100644
+--- a/src/java.base/unix/native/libnet/net_util_md.h
++++ b/src/java.base/unix/native/libnet/net_util_md.h
+@@ -26,6 +26,9 @@
+ #ifndef NET_UTILS_MD_H
+ #define NET_UTILS_MD_H
+ 
++#ifdef ANDROID
++#include <netinet/in.h>
++#endif
+ #include <netdb.h>
+ #include <poll.h>
+ #include <sys/socket.h>
+diff --git a/src/java.base/unix/native/libnio/fs/UnixNativeDispatcher.c b/src/java.base/unix/native/libnio/fs/UnixNativeDispatcher.c
+index 4b5cfabeb..ad2577495 100644
+--- a/src/java.base/unix/native/libnio/fs/UnixNativeDispatcher.c
++++ b/src/java.base/unix/native/libnio/fs/UnixNativeDispatcher.c
+@@ -217,6 +217,41 @@ static fdopendir_func* my_fdopendir_func = NULL;
+ static statx_func* my_statx_func = NULL;
+ #endif
+ 
++#ifdef __ANDROID__
++/*
++ * TODO: Android lacks support for the methods listed below.  In it's place are
++ * alternatives that use existing Android functionality, but lack reentrant
++ * support.  Determine if the following are the most suitable alternatives.
++ *
++ */
++int getgrgid_r(gid_t gid, struct group* grp, char* buf, size_t buflen, struct group** result) {
++
++  *result = NULL;
++  errno = 0;
++  grp = getgrgid(gid);
++  if (grp == NULL) {
++        return errno;
++  }
++  // buf not used by caller (see below)
++  *result = grp;
++  return 0;
++}
++
++int getgrnam_r(const char *name, struct group* grp, char* buf, size_t buflen, struct group** result) {
++
++  *result = NULL;
++  errno = 0;
++  grp = getgrnam(name);
++  if (grp == NULL) {
++        return errno;
++  }
++  // buf not used by caller (see below)
++  *result = grp;
++  return 0;
++
++}
++#endif
++
+ /**
+  * fstatat missing from glibc on Linux.
+  */
+@@ -375,7 +410,7 @@ Java_sun_nio_fs_UnixNativeDispatcher_init(JNIEnv* env, jclass this)
+ #ifdef _DARWIN_FEATURE_64_BIT_INODE
+     capabilities |= sun_nio_fs_UnixNativeDispatcher_SUPPORTS_BIRTHTIME;
+ #endif
+-#if defined(__linux__)
++#if defined(__linux__) && !defined(__ANDROID__)
+     my_statx_func = (statx_func*) dlsym(RTLD_DEFAULT, "statx");
+     if (my_statx_func != NULL) {
+         capabilities |= sun_nio_fs_UnixNativeDispatcher_SUPPORTS_BIRTHTIME;
+diff --git a/src/java.desktop/unix/native/libawt/awt/awt_LoadLibrary.c b/src/java.desktop/unix/native/libawt/awt/awt_LoadLibrary.c
+index af50fdbb5..a061154da 100644
+--- a/src/java.desktop/unix/native/libawt/awt/awt_LoadLibrary.c
++++ b/src/java.desktop/unix/native/libawt/awt/awt_LoadLibrary.c
+@@ -30,6 +30,7 @@
+ #include <jni.h>
+ #include <jni_util.h>
+ #include <jvm.h>
++#include <stdbool.h>
+ #include "gdefs.h"
+ 
+ #include <sys/param.h>
+@@ -95,6 +96,30 @@ JNIEXPORT jboolean JNICALL AWTIsHeadless() {
+   #define HEADLESS_PATH "/libawt_headless.so"
+ #endif
+ 
++static bool read_so_path_from_maps(const char* so_name, char* buf) {
++  FILE *fp = fopen("/proc/self/maps", "r");
++
++  if (!fp) {
++    return false;
++  }
++
++  char maps_buffer[2048];
++  while (fgets(maps_buffer, 2048, fp) != NULL) {
++    if (strstr(maps_buffer, so_name) == NULL) {
++      continue;
++    }
++
++    char *so_path = strchr(maps_buffer, '/');
++    so_path[strlen(so_path) - 1] = '\0'; // Cut trailing \n
++      strcpy(buf,so_path);
++    fclose(fp);
++    return true;
++  }
++
++  fclose(fp);
++  return false;
++}
++
+ jint
+ AWT_OnLoad(JavaVM *vm, void *reserved)
+ {
+@@ -136,6 +161,8 @@ AWT_OnLoad(JavaVM *vm, void *reserved)
+         dladdr((void *)AWT_OnLoad, &dlinfo);
+         if (realpath((char *)dlinfo.dli_fname, buf) == NULL) {
+             perror((char *)dlinfo.dli_fname);
++        } else{
++            read_so_path_from_maps(dlinfo.dli_fname, buf);
+         }
+         len = strlen(buf);
+         p = strrchr(buf, '/');
+diff --git a/src/java.instrument/unix/native/libinstrument/EncodingSupport_md.c b/src/java.instrument/unix/native/libinstrument/EncodingSupport_md.c
+index 490eea9a5..27ee1c23e 100644
+--- a/src/java.instrument/unix/native/libinstrument/EncodingSupport_md.c
++++ b/src/java.instrument/unix/native/libinstrument/EncodingSupport_md.c
+@@ -65,7 +65,11 @@ utfInitialize(void)
+     (void)setlocale(LC_ALL, "");
+ 
+     /* Get the codeset name */
++#ifndef __ANDROID__
+     codeset = (char*)nl_langinfo(CODESET);
++#else
++    codeset = "ASCII"; // (MB_CUR_MAX == 1) ? "ASCII" : "UTF-8";
++#endif
+     if ( codeset == NULL || codeset[0] == 0 ) {
+         UTF_DEBUG(("NO codeset returned by nl_langinfo(CODESET)\n"));
+         return;
+diff --git a/src/jdk.jdwp.agent/share/native/libjdwp/utf_util.c b/src/jdk.jdwp.agent/share/native/libjdwp/utf_util.c
+index 6bae02fce..9cf2a7ab4 100644
+--- a/src/jdk.jdwp.agent/share/native/libjdwp/utf_util.c
++++ b/src/jdk.jdwp.agent/share/native/libjdwp/utf_util.c
+@@ -483,7 +483,11 @@ static int iconvConvert(conv_direction drn, char *bytes, size_t len, char *outpu
+         // locale is not initialized, do it now
+         if (setlocale(LC_ALL, "") != NULL) {
+             // nl_langinfo returns ANSI_X3.4-1968 by default
++#ifndef __ANDROID__
+             codeset = (char*)nl_langinfo(CODESET);
++#else
++            codeset = "ASCII";
++#endif
+         }
+ 
+         if (codeset == NULL) {
-- 
2.39.5

