From ee46066fef265e69f8e0b4842079afc7d8bfa263 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Fri, 24 Jan 2025 22:18:01 +0100 Subject: [PATCH] Add build support for Android+CoreCLR (#110471) This change adds build support for the arm64 and x64 CoreCLR runtimes for Android. Initial infrastructure to run a simple sample was also added (src/mono/sample/Android) and we plan to do more in a follow up. The arm32 and x86 builds are blocked by https://github.com/dotnet/runtime/issues/111665 since our min API level target is 21. Both will be fixed at a later time. Contributes to https://github.com/dotnet/runtime/issues/111491 --------- Co-authored-by: Steve Pfister Co-authored-by: Jan Vorlicek Co-authored-by: Ivan Povazan Co-authored-by: Milos Kotlar --- Directory.Build.props | 2 +- eng/Subsets.props | 9 +- eng/build.sh | 2 +- eng/native/build-commons.sh | 9 +- eng/native/configureplatform.cmake | 5 + eng/native/naming.props | 26 ++ eng/native/tryrun.cmake | 53 ++-- .../templates/build-perf-sample-apps.yml | 2 +- src/coreclr/.nuget/coreclr-packages.proj | 4 +- src/coreclr/CMakeLists.txt | 6 +- src/coreclr/clrfeatures.cmake | 2 +- src/coreclr/crossgen-corelib.proj | 4 +- .../dlls/mscoree/coreclr/CMakeLists.txt | 4 - src/coreclr/hosts/inc/coreclrhost.h | 6 + src/coreclr/inc/crosscomp.h | 9 +- src/coreclr/minipal/Unix/doublemapping.cpp | 10 +- src/coreclr/pal/src/configure.cmake | 3 +- .../pal/src/eventprovider/CMakeLists.txt | 2 +- src/coreclr/pal/src/map/map.cpp | 3 + src/coreclr/runtime.proj | 8 +- src/coreclr/tools/aot/AotCompilerCommon.props | 7 + .../tools/aot/ILCompiler/ILCompiler.props | 4 +- .../aot/ILCompiler/ILCompiler_inbuild.csproj | 2 +- .../tools/aot/crossgen2/crossgen2.props | 4 +- .../aot/crossgen2/crossgen2_inbuild.csproj | 2 +- src/coreclr/vm/amd64/asmhelpers.S | 5 +- src/coreclr/vm/arm64/asmhelpers.S | 2 + src/coreclr/vm/threadstatics.cpp | 15 +- ...rosoft.NETCore.App.Runtime.CoreCLR.sfxproj | 4 +- .../sample/Android/AndroidSampleApp.csproj | 34 ++- src/mono/sample/Android/Makefile | 36 ++- src/native/containers/dn-simdhash-utils.h | 2 +- .../corehost/apphost/static/CMakeLists.txt | 20 +- .../external/libunwind_extras/CMakeLists.txt | 5 + .../CMakeLists.txt | 7 +- .../AndroidAppBuilder/AndroidAppBuilder.cs | 3 + src/tasks/AndroidAppBuilder/ApkBuilder.cs | 45 +++- .../Templates/CMakeLists-android.txt | 2 +- .../Templates/monodroid-coreclr.c | 230 ++++++++++++++++++ .../ResolveReadyToRunCompilers.cs | 4 +- 40 files changed, 491 insertions(+), 111 deletions(-) create mode 100644 src/tasks/AndroidAppBuilder/Templates/monodroid-coreclr.c diff --git a/Directory.Build.props b/Directory.Build.props index 79ec992824c389..7b78bd6efc0f6b 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -231,7 +231,7 @@ <_packageOS>$(_portableOS) - <_packageOS Condition="'$(CrossBuild)' == 'true' and '$(_portableOS)' != 'linux-musl' and '$(_portableOS)' != 'linux-bionic'">$(_hostOS) + <_packageOS Condition="'$(CrossBuild)' == 'true' and '$(_portableOS)' != 'linux-musl' and '$(_portableOS)' != 'linux-bionic' and '$(_portableOS)' != 'android'">$(_hostOS) $(PackageOS)-$(TargetArchitecture) diff --git a/eng/Subsets.props b/eng/Subsets.props index 75c23299daa902..502fd50fbc25c5 100644 --- a/eng/Subsets.props +++ b/eng/Subsets.props @@ -28,6 +28,10 @@ <_CoreCLRSupportedOS Condition="'$(TargetsMobile)' != 'true' and '$(TargetsLinuxBionic)' != 'true'">true + + + <_CoreCLRSupportedOS Condition="'$(TargetsAndroid)' == 'true' and '$(TargetArchitecture)' != 'arm' and '$(TargetArchitecture)' != 'x86'">true + <_CoreCLRSupportedArch Condition="'$(TargetArchitecture)' != 'armv6' and '$(TargetArchitecture)' != 'ppc64le' and '$(TargetArchitecture)' != 's390x'">true true @@ -56,6 +60,7 @@ clr+mono+libs+tools+host+packs mono+libs+packs + clr.runtime+clr.alljits+clr.corelib+clr.nativecorelib+clr.tools+clr.packages+mono+libs+host+packs clr.nativeaotruntime+clr.nativeaotlibs+mono+libs+packs clr.nativeaotruntime+clr.nativeaotlibs+mono+libs+host+packs clr.nativeaotruntime+clr.nativeaotlibs+libs+packs @@ -80,9 +85,11 @@ <_subset Condition="'$(Subset)' != ''">+$(Subset.ToLowerInvariant())+ <_subset Condition="'$(Subset)' == ''">+$(DefaultSubsets)+ + CoreCLR + CoreCLR Mono Mono $(PrimaryRuntimeFlavor) @@ -310,7 +317,7 @@ The cross tools are used as part of the build process with the downloaded build tools, so we need to build them for the host architecture and build them as unsanitized binaries. --> - <_BuildAnyCrossArch Condition="'$(CrossBuild)' == 'true' or '$(BuildArchitecture)' != '$(TargetArchitecture)' or '$(EnableNativeSanitizers)' != ''">true + <_BuildAnyCrossArch Condition="'$(CrossBuild)' == 'true' or '$(BuildArchitecture)' != '$(TargetArchitecture)' or '$(HostOS)' != '$(TargetOS)' or '$(EnableNativeSanitizers)' != ''">true <_BuildCrossComponents Condition="$(_subset.Contains('+clr.crossarchtools+'))">true <_BuildCrossComponents Condition="'$(ClrRuntimeBuildSubsets)' != '' and ('$(PrimaryRuntimeFlavor)' == 'CoreCLR' or '$(TargetsMobile)' == 'true')">true <_CrossBitwidthBuild Condition="'$(BuildArchitecture)' == 'x64' and ('$(TargetArchitecture)' == 'x86' or '$(TargetArchitecture)' == 'arm')">true diff --git a/eng/build.sh b/eng/build.sh index 7d5d64b3d1fc50..1cab7739726fa3 100755 --- a/eng/build.sh +++ b/eng/build.sh @@ -140,7 +140,7 @@ initDistroRid() local isCrossBuild="$3" # Only pass ROOTFS_DIR if __DoCrossArchBuild is specified and the current platform is not an Apple platform (that doesn't use rootfs) - if [[ $isCrossBuild == 1 && "$targetOs" != "osx" && "$targetOs" != "ios" && "$targetOs" != "iossimulator" && "$targetOs" != "tvos" && "$targetOs" != "tvossimulator" && "$targetOs" != "maccatalyst" ]]; then + if [[ $isCrossBuild == 1 && "$targetOs" != "osx" && "$targetOs" != "android" && "$targetOs" != "ios" && "$targetOs" != "iossimulator" && "$targetOs" != "tvos" && "$targetOs" != "tvossimulator" && "$targetOs" != "maccatalyst" ]]; then passedRootfsDir=${ROOTFS_DIR} fi initDistroRidGlobal "${targetOs}" "${targetArch}" "${passedRootfsDir}" diff --git a/eng/native/build-commons.sh b/eng/native/build-commons.sh index d86d42417ad82c..bf17618d972ade 100755 --- a/eng/native/build-commons.sh +++ b/eng/native/build-commons.sh @@ -79,15 +79,18 @@ build_native() fi if [[ "$targetOS" == android || "$targetOS" == linux-bionic ]]; then + # Keep in sync with $(AndroidApiLevelMin) in Directory.Build.props in the repository rooot + local ANDROID_API_LEVEL=21 if [[ -z "$ANDROID_NDK_ROOT" ]]; then echo "Error: You need to set the ANDROID_NDK_ROOT environment variable pointing to the Android NDK root." exit 1 fi - cmakeArgs="-C $__RepoRootDir/eng/native/tryrun.cmake $cmakeArgs" + # cmake cache scripts can't see command line args + export ANDROID_BUILD=1 - # keep ANDROID_PLATFORM in sync with SetOSTargetMinVersions in the root Directory.Build.props - cmakeArgs="-DCMAKE_TOOLCHAIN_FILE=$ANDROID_NDK_ROOT/build/cmake/android.toolchain.cmake -DANDROID_PLATFORM=android-21 $cmakeArgs" + cmakeArgs="-C $__RepoRootDir/eng/native/tryrun.cmake $cmakeArgs" + cmakeArgs="-DCMAKE_TOOLCHAIN_FILE=$ANDROID_NDK_ROOT/build/cmake/android.toolchain.cmake -DANDROID_PLATFORM=android-${ANDROID_API_LEVEL} -DANDROID_NATIVE_API_LEVEL=${ANDROID_API_LEVEL} $cmakeArgs" # Don't try to set CC/CXX in init-compiler.sh - it's handled in android.toolchain.cmake already __Compiler="default" diff --git a/eng/native/configureplatform.cmake b/eng/native/configureplatform.cmake index 10f623e6d59245..6f70e39f30c502 100644 --- a/eng/native/configureplatform.cmake +++ b/eng/native/configureplatform.cmake @@ -514,3 +514,8 @@ if (CLR_CMAKE_TARGET_ANDROID OR CLR_CMAKE_TARGET_MACCATALYST OR CLR_CMAKE_TARGET # - Armv6: zlib-ng has build breaks set(CLR_CMAKE_USE_SYSTEM_ZLIB 1) endif() + +if (NOT CLR_CMAKE_TARGET_ANDROID) + # opt into building tools like ildasm/ilasm + set(CLR_CMAKE_BUILD_TOOLS 1) +endif() diff --git a/eng/native/naming.props b/eng/native/naming.props index b50c0c131cda5e..aa59f00c79030e 100644 --- a/eng/native/naming.props +++ b/eng/native/naming.props @@ -5,6 +5,32 @@ + + + + .dll + .lib + .pdb + + + + + lib + .dylib + .a + .dwarf + + + + + lib + .so + .a + .dbg + + + + diff --git a/eng/native/tryrun.cmake b/eng/native/tryrun.cmake index f952d7e034103d..8fd127f9e3e802 100644 --- a/eng/native/tryrun.cmake +++ b/eng/native/tryrun.cmake @@ -1,8 +1,9 @@ set(CROSS_ROOTFS $ENV{ROOTFS_DIR}) set(TARGET_ARCH_NAME $ENV{TARGET_BUILD_ARCH}) +set(ANDROID_BUILD $ENV{ANDROID_BUILD}) # Also allow building as Android without specifying `-cross`. -if(NOT DEFINED TARGET_ARCH_NAME AND DEFINED ANDROID_PLATFORM) +if(NOT DEFINED TARGET_ARCH_NAME AND DEFINED ANDROID_BUILD) if(ANDROID_ABI STREQUAL "arm64-v8a") set(TARGET_ARCH_NAME "arm64") elseif(ANDROID_ABI STREQUAL "x86_64") @@ -21,34 +22,36 @@ macro(set_cache_value) set(${ARGV0}__TRYRUN_OUTPUT "dummy output" CACHE STRING "Output from TRY_RUN" FORCE) endmacro() -if(EXISTS ${CROSS_ROOTFS}/usr/lib/gcc/armv7-alpine-linux-musleabihf OR - EXISTS ${CROSS_ROOTFS}/usr/lib/gcc/armv6-alpine-linux-musleabihf OR - EXISTS ${CROSS_ROOTFS}/usr/lib/gcc/aarch64-alpine-linux-musl OR - EXISTS ${CROSS_ROOTFS}/usr/lib/gcc/s390x-alpine-linux-musl OR - EXISTS ${CROSS_ROOTFS}/usr/lib/gcc/ppc64le-alpine-linux-musl OR - EXISTS ${CROSS_ROOTFS}/usr/lib/gcc/i586-alpine-linux-musl OR - EXISTS ${CROSS_ROOTFS}/usr/lib/gcc/x86_64-alpine-linux-musl OR - EXISTS ${CROSS_ROOTFS}/usr/lib/gcc/riscv64-alpine-linux-musl) +if(NOT DEFINED ANDROID_BUILD) + if(EXISTS ${CROSS_ROOTFS}/usr/lib/gcc/armv7-alpine-linux-musleabihf OR + EXISTS ${CROSS_ROOTFS}/usr/lib/gcc/armv6-alpine-linux-musleabihf OR + EXISTS ${CROSS_ROOTFS}/usr/lib/gcc/aarch64-alpine-linux-musl OR + EXISTS ${CROSS_ROOTFS}/usr/lib/gcc/s390x-alpine-linux-musl OR + EXISTS ${CROSS_ROOTFS}/usr/lib/gcc/ppc64le-alpine-linux-musl OR + EXISTS ${CROSS_ROOTFS}/usr/lib/gcc/i586-alpine-linux-musl OR + EXISTS ${CROSS_ROOTFS}/usr/lib/gcc/x86_64-alpine-linux-musl OR + EXISTS ${CROSS_ROOTFS}/usr/lib/gcc/riscv64-alpine-linux-musl) - set(ALPINE_LINUX 1) -elseif(EXISTS ${CROSS_ROOTFS}/bin/freebsd-version) - set(FREEBSD 1) - set(CMAKE_SYSTEM_NAME FreeBSD) - set(CLR_CMAKE_TARGET_OS freebsd) -elseif(EXISTS ${CROSS_ROOTFS}/usr/platform/i86pc) - set(ILLUMOS 1) - set(CLR_CMAKE_TARGET_OS sunos) -elseif(EXISTS /System/Library/CoreServices) - set(DARWIN 1) -elseif(EXISTS ${CROSS_ROOTFS}/etc/tizen-release) - set(TIZEN 1) -elseif(EXISTS ${CROSS_ROOTFS}/boot/system/develop/headers/config/HaikuConfig.h) - set(HAIKU 1) - set(CLR_CMAKE_TARGET_OS haiku) + set(ALPINE_LINUX 1) + elseif(EXISTS ${CROSS_ROOTFS}/bin/freebsd-version) + set(FREEBSD 1) + set(CMAKE_SYSTEM_NAME FreeBSD) + set(CLR_CMAKE_TARGET_OS freebsd) + elseif(EXISTS ${CROSS_ROOTFS}/usr/platform/i86pc) + set(ILLUMOS 1) + set(CLR_CMAKE_TARGET_OS sunos) + elseif(EXISTS /System/Library/CoreServices) + set(DARWIN 1) + elseif(EXISTS ${CROSS_ROOTFS}/etc/tizen-release) + set(TIZEN 1) + elseif(EXISTS ${CROSS_ROOTFS}/boot/system/develop/headers/config/HaikuConfig.h) + set(HAIKU 1) + set(CLR_CMAKE_TARGET_OS haiku) + endif() endif() if(DARWIN) - if(TARGET_ARCH_NAME MATCHES "^(arm64|x64)$") + if(DEFINED ANDROID_BUILD OR TARGET_ARCH_NAME MATCHES "^(arm64|x64)$") set_cache_value(HAS_POSIX_SEMAPHORES_EXITCODE 1) set_cache_value(HAVE_BROKEN_FIFO_KEVENT_EXITCODE 1) set_cache_value(HAVE_BROKEN_FIFO_SELECT_EXITCODE 1) diff --git a/eng/pipelines/coreclr/templates/build-perf-sample-apps.yml b/eng/pipelines/coreclr/templates/build-perf-sample-apps.yml index 901078393fab8e..b1855727e127fd 100644 --- a/eng/pipelines/coreclr/templates/build-perf-sample-apps.yml +++ b/eng/pipelines/coreclr/templates/build-perf-sample-apps.yml @@ -21,7 +21,7 @@ parameters: steps: # Build Android sample app - ${{ if eq(parameters.osGroup, 'android') }}: - - script: make run MONO_ARCH=arm64 DEPLOY_AND_RUN=false + - script: make run TARGET_ARCH=arm64 DEPLOY_AND_RUN=false workingDirectory: $(Build.SourcesDirectory)/src/mono/sample/Android displayName: Build HelloAndroid sample app - template: /eng/pipelines/common/upload-artifact-step.yml diff --git a/src/coreclr/.nuget/coreclr-packages.proj b/src/coreclr/.nuget/coreclr-packages.proj index f7c43af0e783cd..a487f999ffd023 100644 --- a/src/coreclr/.nuget/coreclr-packages.proj +++ b/src/coreclr/.nuget/coreclr-packages.proj @@ -9,11 +9,11 @@ - + - + diff --git a/src/coreclr/CMakeLists.txt b/src/coreclr/CMakeLists.txt index 6c14476a0ca992..e519e1e71e5ae8 100644 --- a/src/coreclr/CMakeLists.txt +++ b/src/coreclr/CMakeLists.txt @@ -249,8 +249,10 @@ if(NOT CLR_CMAKE_HOST_TVOS) add_subdirectory(utilcode) add_subdirectory(inc) - add_subdirectory(ilasm) - add_subdirectory(ildasm) + if (CLR_CMAKE_BUILD_TOOLS) + add_subdirectory(ilasm) + add_subdirectory(ildasm) + endif(CLR_CMAKE_BUILD_TOOLS) add_subdirectory(gcinfo) add_subdirectory(jit) add_subdirectory(vm) diff --git a/src/coreclr/clrfeatures.cmake b/src/coreclr/clrfeatures.cmake index 2bf7216af1b4db..a82ab511272c63 100644 --- a/src/coreclr/clrfeatures.cmake +++ b/src/coreclr/clrfeatures.cmake @@ -38,4 +38,4 @@ endif() if (CLR_CMAKE_TARGET_WIN32) set(FEATURE_TYPEEQUIVALENCE 1) -endif(CLR_CMAKE_TARGET_WIN32) +endif(CLR_CMAKE_TARGET_WIN32) \ No newline at end of file diff --git a/src/coreclr/crossgen-corelib.proj b/src/coreclr/crossgen-corelib.proj index ed54fc3cf11faf..7e93e2fcf9b24b 100644 --- a/src/coreclr/crossgen-corelib.proj +++ b/src/coreclr/crossgen-corelib.proj @@ -113,7 +113,9 @@ $(CrossGenDllCmd) -o:$(CoreLibOutputPath) $(CrossGenDllCmd) -r:$([MSBuild]::NormalizePath('$(BinDir)', 'IL', '*.dll')) $(CrossGenDllCmd) --targetarch:$(TargetArchitecture) - $(CrossGenDllCmd) --targetos:$(TargetOS) + $(CrossGenDllCmd) --targetos:$(TargetOS) + + $(CrossGenDllCmd) --targetos:linux $(CrossGenDllCmd) -m:$(MergedMibcPath) --embed-pgo-data $(CrossGenDllCmd) -O $(CrossGenDllCmd) --verify-type-and-field-layout diff --git a/src/coreclr/dlls/mscoree/coreclr/CMakeLists.txt b/src/coreclr/dlls/mscoree/coreclr/CMakeLists.txt index 1fe455a2e393d9..5e2cc50384cbff 100644 --- a/src/coreclr/dlls/mscoree/coreclr/CMakeLists.txt +++ b/src/coreclr/dlls/mscoree/coreclr/CMakeLists.txt @@ -58,10 +58,6 @@ else(CLR_CMAKE_HOST_WIN32) set_exports_linker_option(${EXPORTS_FILE}) - if(CLR_CMAKE_TARGET_ANDROID AND CLR_CMAKE_HOST_ARCH_ARM) - set(EXPORTS_LINKER_OPTION "${EXPORTS_LINKER_OPTION} -Wl,--no-warn-shared-textrel") - endif(CLR_CMAKE_TARGET_ANDROID AND CLR_CMAKE_HOST_ARCH_ARM) - endif (CLR_CMAKE_HOST_WIN32) add_definitions(-DFX_VER_INTERNALNAME_STR=CoreCLR.dll) diff --git a/src/coreclr/hosts/inc/coreclrhost.h b/src/coreclr/hosts/inc/coreclrhost.h index 8c85a1b5276ba7..b57ed1beb38e9d 100644 --- a/src/coreclr/hosts/inc/coreclrhost.h +++ b/src/coreclr/hosts/inc/coreclrhost.h @@ -22,6 +22,12 @@ #include +#ifdef __cplusplus +#define CORECLR_HOSTING_API_LINKAGE extern "C" +#else +#define CORECLR_HOSTING_API_LINKAGE +#endif + // For each hosting API, we define a function prototype and a function pointer // The prototype is useful for implicit linking against the dynamic coreclr // library and the pointer for explicit dynamic loading (dlopen, LoadLibrary) diff --git a/src/coreclr/inc/crosscomp.h b/src/coreclr/inc/crosscomp.h index 496d1c0247533e..32f79ed5c3db97 100644 --- a/src/coreclr/inc/crosscomp.h +++ b/src/coreclr/inc/crosscomp.h @@ -696,15 +696,15 @@ typedef struct _T_KNONVOLATILE_CONTEXT_POINTERS { #define DAC_CS_NATIVE_DATA_SIZE 24 #elif defined(TARGET_FREEBSD) && defined(TARGET_ARM64) #define DAC_CS_NATIVE_DATA_SIZE 24 -#elif defined(TARGET_LINUX) && defined(TARGET_ARM) +#elif (defined(TARGET_LINUX) || defined(TARGET_ANDROID)) && defined(TARGET_ARM) #define DAC_CS_NATIVE_DATA_SIZE 80 -#elif defined(TARGET_LINUX) && defined(TARGET_ARM64) +#elif (defined(TARGET_LINUX) || defined(TARGET_ANDROID)) && defined(TARGET_ARM64) #define DAC_CS_NATIVE_DATA_SIZE 104 #elif defined(TARGET_LINUX) && defined(TARGET_LOONGARCH64) #define DAC_CS_NATIVE_DATA_SIZE 96 -#elif defined(TARGET_LINUX) && defined(TARGET_X86) +#elif (defined(TARGET_LINUX) || defined(TARGET_ANDROID)) && defined(TARGET_X86) #define DAC_CS_NATIVE_DATA_SIZE 76 -#elif defined(TARGET_LINUX) && defined(TARGET_AMD64) +#elif (defined(TARGET_LINUX) || defined(TARGET_ANDROID)) && defined(TARGET_AMD64) #define DAC_CS_NATIVE_DATA_SIZE 96 #elif defined(TARGET_LINUX) && defined(TARGET_S390X) #define DAC_CS_NATIVE_DATA_SIZE 96 @@ -748,4 +748,3 @@ struct T_CRITICAL_SECTION { #else #define T_CRITICAL_SECTION CRITICAL_SECTION #endif - diff --git a/src/coreclr/minipal/Unix/doublemapping.cpp b/src/coreclr/minipal/Unix/doublemapping.cpp index 35879fdc6b5cef..b866da9f93e6f1 100644 --- a/src/coreclr/minipal/Unix/doublemapping.cpp +++ b/src/coreclr/minipal/Unix/doublemapping.cpp @@ -18,6 +18,9 @@ #include #include // __NR_memfd_create #define memfd_create(...) syscall(__NR_memfd_create, __VA_ARGS__) +#elif defined(TARGET_ANDROID) +#include // __NR_memfd_create +#define memfd_create(...) syscall(__NR_memfd_create, __VA_ARGS__) #endif // TARGET_LINUX && !MFD_CLOEXEC #include "minipal.h" #include "minipal/cpufeatures.h" @@ -48,12 +51,13 @@ bool VMToOSInterface::CreateDoubleMemoryMapper(void** pHandle, size_t *pMaxExecu #ifdef TARGET_FREEBSD int fd = shm_open(SHM_ANON, O_RDWR | O_CREAT, S_IRWXU); -#elif defined(TARGET_LINUX) +#elif defined(TARGET_LINUX) || defined(TARGET_ANDROID) int fd = memfd_create("doublemapper", MFD_CLOEXEC); #else int fd = -1; -#endif +#ifndef TARGET_ANDROID + // Bionic doesn't have shm_{open,unlink} // POSIX fallback if (fd == -1) { @@ -64,11 +68,13 @@ bool VMToOSInterface::CreateDoubleMemoryMapper(void** pHandle, size_t *pMaxExecu fd = shm_open(name, O_RDWR | O_CREAT | O_EXCL | O_NOFOLLOW, 0600); shm_unlink(name); } +#endif // !TARGET_ANDROID if (fd == -1) { return false; } +#endif if (ftruncate(fd, MaxDoubleMappedSize) == -1) { diff --git a/src/coreclr/pal/src/configure.cmake b/src/coreclr/pal/src/configure.cmake index db41cc5f6a0f6e..bc4f3258b44b3a 100644 --- a/src/coreclr/pal/src/configure.cmake +++ b/src/coreclr/pal/src/configure.cmake @@ -936,7 +936,8 @@ elseif(CLR_CMAKE_TARGET_HAIKU) set(DEADLOCK_WHEN_THREAD_IS_SUSPENDED_WHILE_BLOCKED_ON_MUTEX 0) set(HAVE_SCHED_OTHER_ASSIGNABLE 1) else() # Anything else is Linux - if(NOT HAVE_LTTNG_TRACEPOINT_H AND FEATURE_EVENT_TRACE) + # LTTNG is not available on Android, so don't error out + if(NOT HAVE_LTTNG_TRACEPOINT_H AND NOT CLR_CMAKE_TARGET_ANDROID AND FEATURE_EVENT_TRACE) unset(HAVE_LTTNG_TRACEPOINT_H CACHE) message(FATAL_ERROR "Cannot find liblttng-ust-dev. Try installing liblttng-ust-dev (or the appropriate packages for your platform)") endif() diff --git a/src/coreclr/pal/src/eventprovider/CMakeLists.txt b/src/coreclr/pal/src/eventprovider/CMakeLists.txt index 143206b5c34f54..76bbf56e8e114c 100644 --- a/src/coreclr/pal/src/eventprovider/CMakeLists.txt +++ b/src/coreclr/pal/src/eventprovider/CMakeLists.txt @@ -1,6 +1,6 @@ set(EVENT_MANIFEST ${VM_DIR}/ClrEtwAll.man) -if(CLR_CMAKE_HOST_LINUX) +if(CLR_CMAKE_HOST_LINUX AND NOT CLR_CMAKE_HOST_ANDROID) add_subdirectory(lttngprovider) else() add_subdirectory(dummyprovider) diff --git a/src/coreclr/pal/src/map/map.cpp b/src/coreclr/pal/src/map/map.cpp index 090ce7dc1beb95..35909bd54f8356 100644 --- a/src/coreclr/pal/src/map/map.cpp +++ b/src/coreclr/pal/src/map/map.cpp @@ -2553,6 +2553,8 @@ BOOL MAPMarkSectionAsNotNeeded(LPCVOID lpAddress) } BOOL retval = TRUE; + +#ifndef TARGET_ANDROID CPalThread * pThread = InternalGetCurrentThread(); InternalEnterCriticalSection(pThread, &mapping_critsec); PLIST_ENTRY pLink, pLinkNext = NULL; @@ -2583,6 +2585,7 @@ BOOL MAPMarkSectionAsNotNeeded(LPCVOID lpAddress) } InternalLeaveCriticalSection(pThread, &mapping_critsec); +#endif // TARGET_ANDROID TRACE_(LOADER)("MAPMarkSectionAsNotNeeded returning %d\n", retval); return retval; diff --git a/src/coreclr/runtime.proj b/src/coreclr/runtime.proj index 12e655d9fdedba..3f16f8262b0b6f 100644 --- a/src/coreclr/runtime.proj +++ b/src/coreclr/runtime.proj @@ -78,16 +78,14 @@ <_CoreClrBuildArg Include="-DCMAKE_TOOLCHAIN_FILE=$(ANDROID_NDK_ROOT)/build/cmake/android.toolchain.cmake"/> <_CoreClrBuildArg Include="-DANDROID_NDK=$(ANDROID_NDK_ROOT)"/> - <_CoreClrBuildArg Include="-DANDROID_STL=none"/> - <_CoreClrBuildArg Include="-DANDROID_CPP_FEATURES="no-rtti no-exceptions""/> + <_CoreClrBuildArg Include="-DANDROID_STL=c++_static"/> + <_CoreClrBuildArg Include="-DANDROID_CPP_FEATURES="no-rtti exceptions""/> <_CoreClrBuildArg Include="-DANDROID_PLATFORM=android-$(AndroidApiLevelMin)"/> + <_CoreClrBuildArg Include="-DANDROID_NATIVE_API_LEVEL=$(AndroidApiLevelMin)"/> <_CoreClrBuildArg Condition="'$(Platform)' == 'arm64'" Include="-DANDROID_ABI=arm64-v8a" /> <_CoreClrBuildArg Condition="'$(Platform)' == 'arm'" Include="-DANDROID_ABI=armeabi-v7a" /> <_CoreClrBuildArg Condition="'$(Platform)' == 'x86'" Include="-DANDROID_ABI=x86" /> <_CoreClrBuildArg Condition="'$(Platform)' == 'x64'" Include="-DANDROID_ABI=x86_64" /> - - - <_CoreClrBuildArg Include="-cmakeargs -DFEATURE_EVENT_TRACE=0"/> diff --git a/src/coreclr/tools/aot/AotCompilerCommon.props b/src/coreclr/tools/aot/AotCompilerCommon.props index 847ae3893b1b2d..fc8657654b65c2 100644 --- a/src/coreclr/tools/aot/AotCompilerCommon.props +++ b/src/coreclr/tools/aot/AotCompilerCommon.props @@ -9,4 +9,11 @@ false false + + + <_LibPrefix Condition="'$(CrossHostArch)' == 'true'">$(LibPrefix) + <_LibPrefix Condition="'$(CrossHostArch)' != 'true'">$(HostLibPrefix) + <_LibSuffix Condition="'$(CrossHostArch)' == 'true'">$(LibSuffix) + <_LibSuffix Condition="'$(CrossHostArch)' != 'true'">$(HostLibSuffix) + diff --git a/src/coreclr/tools/aot/ILCompiler/ILCompiler.props b/src/coreclr/tools/aot/ILCompiler/ILCompiler.props index 759302128ef120..dabf8faa22c01b 100644 --- a/src/coreclr/tools/aot/ILCompiler/ILCompiler.props +++ b/src/coreclr/tools/aot/ILCompiler/ILCompiler.props @@ -64,7 +64,7 @@ $(CrossHostArch) arm - $(LibPrefix)jitinterface_$(TargetArchitectureForSharedLibraries)$(LibSuffix) + $(_LibPrefix)jitinterface_$(TargetArchitectureForSharedLibraries)$(_LibSuffix) $(RuntimeBinDir)$(CrossHostArch) @@ -76,7 +76,7 @@ Link="%(FileName)%(Extension)" /> - - $(BuildArchitecture) + $(BuildArchitecture) <_IsPublishing>true $(NETCoreSdkRuntimeIdentifier) $(RuntimeBinDir)$(BuildArchitecture)/ilc/ diff --git a/src/coreclr/tools/aot/crossgen2/crossgen2.props b/src/coreclr/tools/aot/crossgen2/crossgen2.props index ea899f9b866f5f..2ec464eaa54bd5 100644 --- a/src/coreclr/tools/aot/crossgen2/crossgen2.props +++ b/src/coreclr/tools/aot/crossgen2/crossgen2.props @@ -48,7 +48,7 @@ $(CrossHostArch) arm - $(LibPrefix)jitinterface_$(TargetArchitectureForSharedLibraries)$(LibSuffix) + $(_LibPrefix)jitinterface_$(TargetArchitectureForSharedLibraries)$(_LibSuffix) @@ -58,7 +58,7 @@ Link="%(FileName)%(Extension)" /> - - $(BuildArchitecture) + $(BuildArchitecture) <_IsPublishing>true $(NETCoreSdkRuntimeIdentifier) $(RuntimeBinDir)$(BuildArchitecture)/crossgen2/ diff --git a/src/coreclr/vm/amd64/asmhelpers.S b/src/coreclr/vm/amd64/asmhelpers.S index 6b3883528e6f80..9f1912fae03242 100644 --- a/src/coreclr/vm/amd64/asmhelpers.S +++ b/src/coreclr/vm/amd64/asmhelpers.S @@ -296,6 +296,8 @@ LEAF_END GetThreadVarsAddress, _TEXT #ifndef TARGET_APPLE # EXTERN_C void* GetTlsIndexObjectDescOffset(); +#ifndef TARGET_ANDROID + # # Helper to calculate the offset of native thread local variable `t_ThreadStatics`. The offset has to be found at runtime # once linker does its relocation and fixup of thread locals. The runtime gets the address of this function, so @@ -318,7 +320,8 @@ LEAF_ENTRY GetTlsIndexObjectDescOffset, _TEXT call EXTERNAL_C_FUNC(__tls_get_addr) # dummy call to have linker see the code pattern to replace the offset int 3 LEAF_END GetTlsIndexObjectDescOffset, _TEXT -#endif +#endif // !TARGET_ANDROID +#endif // !TARGET_OSX LEAF_ENTRY JIT_PollGC, _TEXT PREPARE_EXTERNAL_VAR g_TrapReturningThreads, rax diff --git a/src/coreclr/vm/arm64/asmhelpers.S b/src/coreclr/vm/arm64/asmhelpers.S index 2f6390e3724ed0..a6801090ad9b25 100644 --- a/src/coreclr/vm/arm64/asmhelpers.S +++ b/src/coreclr/vm/arm64/asmhelpers.S @@ -777,6 +777,7 @@ LEAF_END GetThreadVarsAddress, _TEXT // ------------------------------------------------------------------ // size_t GetThreadStaticsVariableOffset() +#ifndef TARGET_ANDROID // Helper to calculate the offset of native thread local variable `t_ThreadStatics` in TCB. The offset has to be found at runtime // once linker does its relocation and fixup of thread locals. The offset, after calculation is returned in `x0` register. @@ -805,6 +806,7 @@ LEAF_ENTRY GetTLSResolverAddress, _TEXT EPILOG_RETURN LEAF_END GetTLSResolverAddress, _TEXT // ------------------------------------------------------------------ +#endif // TARGET_ANDROID #endif // !TARGET_APPLE LEAF_ENTRY JIT_PollGC, _TEXT diff --git a/src/coreclr/vm/threadstatics.cpp b/src/coreclr/vm/threadstatics.cpp index 2b773cb317ef41..8c2f7e9588226e 100644 --- a/src/coreclr/vm/threadstatics.cpp +++ b/src/coreclr/vm/threadstatics.cpp @@ -806,7 +806,7 @@ void FreeTLSIndicesForLoaderAllocator(LoaderAllocator *pLoaderAllocator) static void* GetTlsIndexObjectAddress(); -#if !defined(TARGET_APPLE) && defined(TARGET_UNIX) && (defined(TARGET_ARM64) || defined(TARGET_LOONGARCH64)) +#if !defined(TARGET_APPLE) && defined(TARGET_UNIX) && !defined(TARGET_ANDROID) && (defined(TARGET_ARM64) || defined(TARGET_LOONGARCH64)) extern "C" size_t GetTLSResolverAddress(); // Check if the resolver address retrieval code is expected. We verify the exact @@ -905,7 +905,7 @@ static bool IsValidTLSResolver() return false; } -#endif // !TARGET_APPLE && TARGET_UNIX && (TARGET_ARM64 || TARGET_LOONGARCH64) +#endif // !TARGET_APPLE && TARGET_UNIX && !TARGET_ANDROID && (TARGET_ARM64 || TARGET_LOONGARCH64) bool CanJITOptimizeTLSAccess() { @@ -924,6 +924,8 @@ bool CanJITOptimizeTLSAccess() // Optimization is disabled for linux musl arm64 #elif defined(TARGET_FREEBSD) && defined(TARGET_ARM64) // Optimization is disabled for FreeBSD/arm64 +#elif defined(TARGET_ANDROID) + // Optimation is disabled for Android until emulated TLS is supported. #elif !defined(TARGET_APPLE) && defined(TARGET_UNIX) && defined(TARGET_ARM64) bool tlsResolverValid = IsValidTLSResolver(); if (tlsResolverValid) @@ -1062,15 +1064,17 @@ static void* GetTlsIndexObjectAddress() return GetThreadStaticDescriptor(p); } -#elif defined(TARGET_ARM64) || defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64) +#elif !defined(TARGET_ANDROID) && defined(TARGET_ARM64) || defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64) extern "C" size_t GetThreadStaticsVariableOffset(); -#endif // TARGET_ARM64 || TARGET_LOONGARCH64 || TARGET_RISCV64 +#endif // !TARGET_ANDROID && TARGET_ARM64 || TARGET_LOONGARCH64 || TARGET_RISCV64 #endif // TARGET_WINDOWS void GetThreadLocalStaticBlocksInfo(CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo) { + +#if !defined(TARGET_ANDROID) STANDARD_VM_CONTRACT; size_t threadStaticBaseOffset = 0; @@ -1100,12 +1104,13 @@ void GetThreadLocalStaticBlocksInfo(CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo) threadStaticBaseOffset = GetThreadStaticsVariableOffset(); #else - _ASSERTE_MSG(false, "Unsupported scenario of optimizing TLS access on Linux Arm32/x86"); + _ASSERTE_MSG(false, "Unsupported scenario of optimizing TLS access on Linux Arm32/x86 and Android"); #endif // TARGET_WINDOWS pInfo->offsetOfMaxThreadStaticBlocks = (uint32_t)(threadStaticBaseOffset + offsetof(ThreadLocalData, cNonCollectibleTlsData)); pInfo->offsetOfThreadStaticBlocks = (uint32_t)(threadStaticBaseOffset + offsetof(ThreadLocalData, pNonCollectibleTlsArrayData)); pInfo->offsetOfBaseOfThreadLocalData = (uint32_t)threadStaticBaseOffset; +#endif // !TARGET_ANDROID } #endif // !DACCESS_COMPILE diff --git a/src/installer/pkg/sfx/Microsoft.NETCore.App/Microsoft.NETCore.App.Runtime.CoreCLR.sfxproj b/src/installer/pkg/sfx/Microsoft.NETCore.App/Microsoft.NETCore.App.Runtime.CoreCLR.sfxproj index 18ad16cfff4501..14522c2c74e79e 100644 --- a/src/installer/pkg/sfx/Microsoft.NETCore.App/Microsoft.NETCore.App.Runtime.CoreCLR.sfxproj +++ b/src/installer/pkg/sfx/Microsoft.NETCore.App/Microsoft.NETCore.App.Runtime.CoreCLR.sfxproj @@ -42,12 +42,14 @@ $([MSBuild]::NormalizePath('$(Crossgen2InBuildDir)', 'crossgen2$(ExeSuffix)')) + <_CrossGenTargetOS Condition="'$(TargetsAndroid)' != 'true'">$(TargetOS) + <_CrossGenTargetOS Condition="'$(TargetsAndroid)' == 'true'">linux diff --git a/src/mono/sample/Android/AndroidSampleApp.csproj b/src/mono/sample/Android/AndroidSampleApp.csproj index 573b44ee710530..43e92d34c84818 100644 --- a/src/mono/sample/Android/AndroidSampleApp.csproj +++ b/src/mono/sample/Android/AndroidSampleApp.csproj @@ -1,5 +1,6 @@ + Mono Exe false $(NetCoreAppCurrent) @@ -11,19 +12,20 @@ - + - - - + <_MobileIntermediateOutputPath>$(IntermediateOutputPath)mobile @@ -34,7 +36,7 @@ $(PublishDir)apk\ - + @(MonoAOTCompilerDefaultAotArguments, ';') @(MonoAOTCompilerDefaultProcessArguments, ';') @@ -42,24 +44,24 @@ + Condition="'$(RuntimeFlavor)' == 'Mono' and '$(ForceAOT)' == 'true'"/> - + - + <_AotOutputType>Library <_AotLibraryFormat>So <_AotMode Condition="'$(AotMode)' == ''">Normal - + <_AotOutputType>AsmOnly <_AotModulesTablePath>$(ApkDir)\modules.c <_AotMode Condition="'$(AotMode)' == ''">Full @@ -69,7 +71,7 @@ 21 - + <_AsPrefixPath>$([MSBuild]::EnsureTrailingSlash('$(_AsPrefixPath)')) <_ToolPrefixPath>$([MSBuild]::EnsureTrailingSlash('$(_ToolPrefixPath)')) @@ -88,7 +90,7 @@ <_AsName>clang - + + $(MicrosoftNetCoreAppRuntimePackDir)runtimes\android-$(TargetArchitecture)\native\include\mono-2.0 + $(CoreClrProjectRoot)hosts\inc + + @@ -158,4 +165,5 @@ + diff --git a/src/mono/sample/Android/Makefile b/src/mono/sample/Android/Makefile index 64f5e13a5e89a6..82539298194b20 100644 --- a/src/mono/sample/Android/Makefile +++ b/src/mono/sample/Android/Makefile @@ -1,11 +1,12 @@ -MONO_CONFIG=Release -MONO_ARCH?=x64 +BUILD_CONFIG=Release +TARGET_ARCH?=x64 DOTNET := ../../../../dotnet.sh USE_LLVM=true AOT=false AOT_WITH_LIBRARY_FILES=false INTERP=false DEPLOY_AND_RUN?=true +RUNTIME_FLAVOR?=Mono #If DIAGNOSTIC_PORTS is enabled, @(RuntimeComponents) must also include 'diagnostics_tracing'. #If @(RuntimeComponents) includes 'diagnostics_tracing', DIAGNOSTIC_PORTS is optional. @@ -14,16 +15,30 @@ DEPLOY_AND_RUN?=true #DIAGNOSTIC_PORTS=10.0.2.2:9000,suspend #DIAGNOSTIC_PORTS=$(DOTNET_DiagnosticPorts) -all: runtimepack run +TOP=../../../../ +REPO_DIR=$(realpath $(TOP)) +TASKS_DIR=$(REPO_DIR)/src/tasks +DOTNET=$(REPO_DIR)/dotnet.sh +BUILD_SCRIPT=$(REPO_DIR)/build.sh +all: appbuilder runtimepack run + +appbuilder: + $(DOTNET) build -c $(BUILD_CONFIG) $(TASKS_DIR)/AndroidAppBuilder/AndroidAppBuilder.csproj + +ifeq ($(RUNTIME_FLAVOR),Mono) +runtimepack: + $(BUILD_SCRIPT) mono+libs -os android -arch $(TARGET_ARCH) -c $(BUILD_CONFIG) -bl +else runtimepack: - ../../../../build.sh mono+libs -os android -arch $(MONO_ARCH) -c $(MONO_CONFIG) + $(BUILD_SCRIPT) clr.runtime+clr.alljits+clr.corelib+clr.nativecorelib+clr.tools+clr.packages+libs -os android -arch $(TARGET_ARCH) -c $(BUILD_CONFIG) -cross -bl +endif -run: +run: appbuilder $(DOTNET) publish \ - /p:TargetArchitecture=$(MONO_ARCH) \ + /p:TargetArchitecture=$(TARGET_ARCH) \ /p:TargetOS=android \ - /p:Configuration=$(MONO_CONFIG) \ + /p:Configuration=$(BUILD_CONFIG) \ /p:DeployAndRun=$(DEPLOY_AND_RUN) \ /p:RunAOTCompilation=$(AOT) \ /p:ForceAOT=$(AOT) \ @@ -31,6 +46,9 @@ run: /p:MonoForceInterpreter=$(INTERP) \ /p:UseLLVM=$(USE_LLVM) \ /p:RunActivity=false \ - '/p:DiagnosticPorts="$(DIAGNOSTIC_PORTS)"' + '/p:DiagnosticPorts="$(DIAGNOSTIC_PORTS)"' \ + /p:RuntimeFlavor=$(RUNTIME_FLAVOR) \ + /bl clean: - rm -rf ../../../../artifacts/bin/AndroidSampleApp + rm -rf $(REPO_DIR)/artifacts/bin/AndroidSampleApp + rm -rf $(REPO_DIR)/artifacts/obj/mono/AndroidSampleApp \ No newline at end of file diff --git a/src/native/containers/dn-simdhash-utils.h b/src/native/containers/dn-simdhash-utils.h index ce14b810974281..91ecdcc4542710 100644 --- a/src/native/containers/dn-simdhash-utils.h +++ b/src/native/containers/dn-simdhash-utils.h @@ -129,7 +129,7 @@ murmur3_scan_forward (const uint8_t *ptr) { // TODO: On wasm we could do a single u32 load then scan the bytes, // as long as we're sure ptr isn't up against the end of memory - murmur3_scan_result_t result = { 0, }; + murmur3_scan_result_t result = { }; // I tried to get a loop to auto-unroll, but GCC only unrolls at O3 and MSVC never does. #define SCAN_1(i) \ diff --git a/src/native/corehost/apphost/static/CMakeLists.txt b/src/native/corehost/apphost/static/CMakeLists.txt index 25c1d55e7360cd..9939ca18493173 100644 --- a/src/native/corehost/apphost/static/CMakeLists.txt +++ b/src/native/corehost/apphost/static/CMakeLists.txt @@ -46,7 +46,10 @@ set(HEADERS ../../fxr_resolver.h ) -add_compile_definitions(NATIVE_LIBS_EMBEDDED) +# TODO: https://github.com/dotnet/runtime/issues/111523 +if (NOT CLR_CMAKE_TARGET_ANDROID) + add_compile_definitions(NATIVE_LIBS_EMBEDDED) +endif() include(../../fxr/files.cmake) include(../../hostpolicy/files.cmake) @@ -169,10 +172,21 @@ else() System.Globalization.Native-Static System.IO.Compression.Native-Static - System.Net.Security.Native-Static System.Native-Static - System.Security.Cryptography.Native.OpenSsl-Static + ) + + if(NOT CLR_CMAKE_TARGET_ANDROID) + list(APPEND NATIVE_LIBS + System.Net.Security.Native-Static + System.Security.Cryptography.Native.OpenSsl-Static + ) + else() + list(APPEND NATIVE_LIBS + System.Security.Cryptography.Native.Android-Static + ) + endif() + list(APPEND NATIVE_LIBS coreclrpal_dac corguids dbgutil diff --git a/src/native/external/libunwind_extras/CMakeLists.txt b/src/native/external/libunwind_extras/CMakeLists.txt index b08325f09e3bf8..8b7b708b702649 100644 --- a/src/native/external/libunwind_extras/CMakeLists.txt +++ b/src/native/external/libunwind_extras/CMakeLists.txt @@ -165,6 +165,11 @@ if(CLR_CMAKE_HOST_WIN32) set_source_files_properties(${LIBUNWIND_SOURCES} PROPERTIES COMPILE_FLAGS /TC) # compile all files as C endif(CLR_CMAKE_HOST_WIN32) +# TODO: https://github.com/dotnet/runtime/issues/111527 +if(CLR_CMAKE_TARGET_ANDROID) + add_compile_options(-Wno-error) +endif() + if(CLR_CMAKE_HOST_UNIX) if(CLR_CMAKE_HOST_APPLE) add_library(libunwind_dac OBJECT ${LIBUNWIND_SOURCES}) diff --git a/src/native/libs/System.Security.Cryptography.Native.Android/CMakeLists.txt b/src/native/libs/System.Security.Cryptography.Native.Android/CMakeLists.txt index f87db8a8c75b61..033378d2ee00ae 100644 --- a/src/native/libs/System.Security.Cryptography.Native.Android/CMakeLists.txt +++ b/src/native/libs/System.Security.Cryptography.Native.Android/CMakeLists.txt @@ -52,5 +52,8 @@ target_link_libraries(System.Security.Cryptography.Native.Android set_target_properties(System.Security.Cryptography.Native.Android PROPERTIES OUTPUT_NAME "System.Security.Cryptography.Native.Android") set_target_properties(System.Security.Cryptography.Native.Android-Static PROPERTIES OUTPUT_NAME "System.Security.Cryptography.Native.Android") -install_with_stripped_symbols (System.Security.Cryptography.Native.Android PROGRAMS .) -install (TARGETS System.Security.Cryptography.Native.Android-Static DESTINATION .) +if (GEN_SHARED_LIB) + install_with_stripped_symbols (System.Security.Cryptography.Native.Android PROGRAMS .) +endif() + +install (TARGETS System.Security.Cryptography.Native.Android-Static DESTINATION ${STATIC_LIB_DESTINATION} COMPONENT libs) diff --git a/src/tasks/AndroidAppBuilder/AndroidAppBuilder.cs b/src/tasks/AndroidAppBuilder/AndroidAppBuilder.cs index 626a6d2b191705..73b1dbaa8af427 100644 --- a/src/tasks/AndroidAppBuilder/AndroidAppBuilder.cs +++ b/src/tasks/AndroidAppBuilder/AndroidAppBuilder.cs @@ -96,6 +96,8 @@ public class AndroidAppBuilderTask : Task public bool StripDebugSymbols { get; set; } + public string RuntimeFlavor { get; set; } = nameof(RuntimeFlavorEnum.Mono); + /// /// Path to a custom MainActivity.java with custom UI /// A default one is used if it's not set @@ -138,6 +140,7 @@ public override bool Execute() apkBuilder.IsLibraryMode = IsLibraryMode; apkBuilder.NativeDependencies = NativeDependencies; apkBuilder.ExtraLinkerArguments = ExtraLinkerArguments; + apkBuilder.RuntimeFlavor = RuntimeFlavor; (ApkBundlePath, ApkPackageId) = apkBuilder.BuildApk(RuntimeIdentifier, MainLibraryFileName, MonoRuntimeHeaders); return true; diff --git a/src/tasks/AndroidAppBuilder/ApkBuilder.cs b/src/tasks/AndroidAppBuilder/ApkBuilder.cs index d947c2f88a29e5..7ed5564638ede9 100644 --- a/src/tasks/AndroidAppBuilder/ApkBuilder.cs +++ b/src/tasks/AndroidAppBuilder/ApkBuilder.cs @@ -11,6 +11,12 @@ using Microsoft.Build.Framework; using Microsoft.Build.Utilities; +public enum RuntimeFlavorEnum +{ + Mono, + CoreCLR +} + public partial class ApkBuilder { private const string DefaultMinApiLevel = "21"; @@ -41,6 +47,8 @@ public partial class ApkBuilder public ITaskItem[] Assemblies { get; set; } = Array.Empty(); public ITaskItem[] ExtraLinkerArguments { get; set; } = Array.Empty(); public string[] NativeDependencies { get; set; } = Array.Empty(); + public string RuntimeFlavor { get; set; } = nameof(RuntimeFlavorEnum.Mono); + private RuntimeFlavorEnum parsedRuntimeFlavor; private TaskLoggingHelper logger; @@ -52,7 +60,7 @@ public ApkBuilder(TaskLoggingHelper logger) public (string apk, string packageId) BuildApk( string runtimeIdentifier, string mainLibraryFileName, - string monoRuntimeHeaders) + string runtimeHeaders) { if (string.IsNullOrEmpty(AppDir) || !Directory.Exists(AppDir)) { @@ -140,6 +148,11 @@ public ApkBuilder(TaskLoggingHelper logger) throw new ArgumentException($"{buildToolsFolder} was not found."); } + if (!Enum.TryParse(RuntimeFlavor, true, out parsedRuntimeFlavor)) + { + throw new ArgumentException($"Unknown RuntimeFlavor value: {RuntimeFlavor}. '{nameof(RuntimeFlavor)}' must be one of: {string.Join(",", Enum.GetNames(typeof(RuntimeFlavorEnum)))}"); + } + var assemblerFiles = new StringBuilder(); var assemblerFilesToLink = new StringBuilder(); var aotLibraryFiles = new List(); @@ -246,23 +259,32 @@ public ApkBuilder(TaskLoggingHelper logger) } else { - string monoRuntimeLib = ""; - if (StaticLinkedRuntime) + string runtimeLib = ""; + if (parsedRuntimeFlavor == RuntimeFlavorEnum.CoreCLR) { - monoRuntimeLib = Path.Combine(AppDir, "libmonosgen-2.0.a"); + if (StaticLinkedRuntime) + throw new ArgumentException("Static linking is not supported for CoreCLR runtime"); + runtimeLib = Path.Combine(AppDir, "libcoreclr.so"); } else { - monoRuntimeLib = Path.Combine(AppDir, "libmonosgen-2.0.so"); + if (StaticLinkedRuntime) + { + runtimeLib = Path.Combine(AppDir, "libmonosgen-2.0.a"); + } + else + { + runtimeLib = Path.Combine(AppDir, "libmonosgen-2.0.so"); + } } - if (!File.Exists(monoRuntimeLib)) + if (!File.Exists(runtimeLib)) { - throw new ArgumentException($"{monoRuntimeLib} was not found"); + throw new ArgumentException($"{runtimeLib} was not found"); } else { - nativeLibraries += $"{monoRuntimeLib}{Environment.NewLine}"; + nativeLibraries += $"{runtimeLib}{Environment.NewLine}"; } if (StaticLinkedRuntime) @@ -297,7 +319,7 @@ public ApkBuilder(TaskLoggingHelper logger) // There's a circular dependency between static mono runtime lib and static component libraries. // Adding mono runtime lib before and after component libs will resolve issues with undefined symbols // due to circular dependency. - nativeLibraries += $" {monoRuntimeLib}{Environment.NewLine}"; + nativeLibraries += $" {runtimeLib}{Environment.NewLine}"; } } @@ -310,10 +332,11 @@ public ApkBuilder(TaskLoggingHelper logger) nativeLibraries += assemblerFilesToLink.ToString(); string aotSources = assemblerFiles.ToString(); - string monodroidSource = (IsLibraryMode) ? "monodroid-librarymode.c" : "monodroid.c"; + string monodroidSource = (parsedRuntimeFlavor == RuntimeFlavorEnum.CoreCLR) ? + "monodroid-coreclr.c" : (IsLibraryMode) ? "monodroid-librarymode.c" : "monodroid.c"; string cmakeLists = Utils.GetEmbeddedResource("CMakeLists-android.txt") - .Replace("%MonoInclude%", monoRuntimeHeaders) + .Replace("%RuntimeInclude%", runtimeHeaders) .Replace("%NativeLibrariesToLink%", nativeLibraries) .Replace("%MONODROID_SOURCE%", monodroidSource) .Replace("%AotSources%", aotSources) diff --git a/src/tasks/AndroidAppBuilder/Templates/CMakeLists-android.txt b/src/tasks/AndroidAppBuilder/Templates/CMakeLists-android.txt index 0f1d68046b29ae..aa118f9dd55770 100644 --- a/src/tasks/AndroidAppBuilder/Templates/CMakeLists-android.txt +++ b/src/tasks/AndroidAppBuilder/Templates/CMakeLists-android.txt @@ -21,7 +21,7 @@ add_library( %Defines% -include_directories("%MonoInclude%") +include_directories("%RuntimeInclude%") target_link_libraries( monodroid diff --git a/src/tasks/AndroidAppBuilder/Templates/monodroid-coreclr.c b/src/tasks/AndroidAppBuilder/Templates/monodroid-coreclr.c new file mode 100644 index 00000000000000..b8fc9b27b59047 --- /dev/null +++ b/src/tasks/AndroidAppBuilder/Templates/monodroid-coreclr.c @@ -0,0 +1,230 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/********* exported symbols *********/ + +/* JNI exports */ + +void +Java_net_dot_MonoRunner_setEnv (JNIEnv* env, jobject thiz, jstring j_key, jstring j_value); + +int +Java_net_dot_MonoRunner_initRuntime (JNIEnv* env, jobject thiz, jstring j_files_dir, jstring j_cache_dir, jstring j_testresults_dir, jstring j_entryPointLibName, jobjectArray j_args, long current_local_time); + +/********* implementation *********/ + +static char *bundle_path; +static char *executable; + +#define LOG_INFO(fmt, ...) __android_log_print(ANDROID_LOG_DEBUG, "DOTNET", fmt, ##__VA_ARGS__) +#define LOG_ERROR(fmt, ...) __android_log_print(ANDROID_LOG_ERROR, "DOTNET", fmt, ##__VA_ARGS__) + +#if defined(__arm__) +#define ANDROID_RUNTIME_IDENTIFIER "android-arm" +#elif defined(__aarch64__) +#define ANDROID_RUNTIME_IDENTIFIER "android-arm64" +#elif defined(__i386__) +#define ANDROID_RUNTIME_IDENTIFIER "android-x86" +#elif defined(__x86_64__) +#define ANDROID_RUNTIME_IDENTIFIER "android-x64" +#else +#error Unknown architecture +#endif + +#define RUNTIMECONFIG_BIN_FILE "runtimeconfig.bin" + +static void +strncpy_str (JNIEnv *env, char *buff, jstring str, int nbuff) +{ + jboolean isCopy = 0; + const char *copy_buff = (*env)->GetStringUTFChars (env, str, &isCopy); + strncpy (buff, copy_buff, nbuff); + if (isCopy) + (*env)->ReleaseStringUTFChars (env, str, copy_buff); +} + +void +Java_net_dot_MonoRunner_setEnv (JNIEnv* env, jobject thiz, jstring j_key, jstring j_value) +{ + LOG_INFO ("Java_net_dot_MonoRunner_setEnv:"); + const char *key = (*env)->GetStringUTFChars(env, j_key, 0); + const char *val = (*env)->GetStringUTFChars(env, j_value, 0); + setenv (key, val, true); + (*env)->ReleaseStringUTFChars(env, j_key, key); + (*env)->ReleaseStringUTFChars(env, j_value, val); +} + +/* +* Get the list of trusted assemblies from a specified @dir_path. +* The path is searched for .dll files which when found are concatenated +* to the output string @tpas separated by ':'. +* The output string should be freed by the caller. +* The return value is the length of the output string. +*/ +static size_t +get_tpas_from_path(const char* dir_path, const char** tpas) +{ + DIR *dir = opendir(dir_path); + if (dir == NULL) + { + LOG_ERROR("Failed to open directory at: %s", dir_path); + return -1; + } + + struct dirent *dir_entry; + size_t dir_path_len = strlen(dir_path); + char *concat_dll_paths = NULL; + size_t concat_dll_paths_len = 0; + + while ((dir_entry = readdir(dir))) + { + if (dir_entry->d_type == DT_REG) + { + size_t file_name_len = strlen(dir_entry->d_name); + // filter out .dll files + if (file_name_len > 4 && strcmp(dir_entry->d_name + file_name_len - 4, ".dll") == 0) + { + size_t curr_dll_path = dir_path_len + file_name_len + 2; // +2 for '/' and ':' + concat_dll_paths_len += curr_dll_path; + concat_dll_paths = realloc(concat_dll_paths, concat_dll_paths_len); + if (concat_dll_paths == NULL) + { + LOG_ERROR("realloc failed while resolving: %s", dir_entry->d_name); + closedir(dir); + return -1; + } + concat_dll_paths[concat_dll_paths_len-curr_dll_path] = '\0'; // adjust previous string end + size_t ret = sprintf(concat_dll_paths, "%s%s/%s:", concat_dll_paths, dir_path, dir_entry->d_name); // concat the current dll path + if (ret != concat_dll_paths_len) + { + LOG_ERROR("sprintf failed while resolving: %s", dir_entry->d_name); + closedir(dir); + return -1; + } + } + } + } + closedir(dir); + + if (concat_dll_paths != NULL && concat_dll_paths_len > 0) { + concat_dll_paths[concat_dll_paths_len - 1] = '\0'; // remove the trailing ':' + } + + *tpas = concat_dll_paths; + return concat_dll_paths_len; +} + +static int +mono_droid_runtime_init (const char* executable, int managed_argc, char* managed_argv[], int local_date_time_offset) +{ + LOG_INFO ("mono_droid_runtime_init called with executable: %s", executable); + + chdir (bundle_path); + + // TODO: set TRUSTED_PLATFORM_ASSEMBLIES, APP_PATHS and NATIVE_DLL_SEARCH_DIRECTORIES + + const char* appctx_keys[3]; + appctx_keys[0] = "RUNTIME_IDENTIFIER"; + appctx_keys[1] = "APP_CONTEXT_BASE_DIRECTORY"; + appctx_keys[2] = "TRUSTED_PLATFORM_ASSEMBLIES"; + + const char* appctx_values[3]; + appctx_values[0] = ANDROID_RUNTIME_IDENTIFIER; + appctx_values[1] = bundle_path; + size_t tpas_len = get_tpas_from_path(bundle_path, &appctx_values[2]); + if (tpas_len < 1) + { + LOG_ERROR("Failed to get trusted assemblies from path: %s", bundle_path); + return -1; + } + + size_t executable_path_len = strlen(bundle_path) + strlen(executable) + 2; // +2 for '/' and '\0' + char* executable_path = (char*)malloc(executable_path_len); + size_t res = sprintf (executable_path, "%s/%s", bundle_path, executable); + if (res != executable_path_len - 1) + { + LOG_ERROR("Failed to resolve full path for: %s", executable); + return -1; + } + executable_path[res] = '\0'; + + unsigned int coreclr_domainId = 0; + void *coreclr_handle = NULL; + + LOG_INFO ("Calling coreclr_initialize"); + int rv = coreclr_initialize ( + executable_path, + executable, + 3, + appctx_keys, + appctx_values, + &coreclr_handle, + &coreclr_domainId + ); + LOG_INFO ("coreclr_initialize returned %d", rv); + + LOG_INFO ("Calling coreclr_execute_assembly"); + coreclr_execute_assembly (coreclr_handle, coreclr_domainId, managed_argc, managed_argv, executable_path, &rv); + + LOG_INFO ("Exit code: %d.", rv); + return rv; +} + +int +Java_net_dot_MonoRunner_initRuntime (JNIEnv* env, jobject thiz, jstring j_files_dir, jstring j_cache_dir, jstring j_testresults_dir, jstring j_entryPointLibName, jobjectArray j_args, long current_local_time) +{ + LOG_INFO ("Java_net_dot_MonoRunner_initRuntime:"); + char file_dir[2048]; + char cache_dir[2048]; + char testresults_dir[2048]; + char entryPointLibName[2048]; + strncpy_str (env, file_dir, j_files_dir, sizeof(file_dir)); + strncpy_str (env, cache_dir, j_cache_dir, sizeof(cache_dir)); + strncpy_str (env, testresults_dir, j_testresults_dir, sizeof(testresults_dir)); + strncpy_str (env, entryPointLibName, j_entryPointLibName, sizeof(entryPointLibName)); + + bundle_path = file_dir; + executable = entryPointLibName; + + setenv ("HOME", bundle_path, true); + setenv ("TMPDIR", cache_dir, true); + setenv ("TEST_RESULTS_DIR", testresults_dir, true); + + int args_len = (*env)->GetArrayLength(env, j_args); + int managed_argc = args_len + 1; + char** managed_argv = (char**)malloc(managed_argc * sizeof(char*)); + + managed_argv[0] = bundle_path; + for (int i = 0; i < args_len; ++i) + { + jstring j_arg = (*env)->GetObjectArrayElement(env, j_args, i); + managed_argv[i + 1] = (char*)((*env)->GetStringUTFChars(env, j_arg, NULL)); + } + + int res = mono_droid_runtime_init (executable, managed_argc, managed_argv, current_local_time); + + for (int i = 0; i < args_len; ++i) + { + jstring j_arg = (*env)->GetObjectArrayElement(env, j_args, i); + (*env)->ReleaseStringUTFChars(env, j_arg, managed_argv[i + 1]); + } + + free(managed_argv); + return res; +} + diff --git a/src/tasks/Crossgen2Tasks/ResolveReadyToRunCompilers.cs b/src/tasks/Crossgen2Tasks/ResolveReadyToRunCompilers.cs index 1ec6c1a090a69b..f265761496de1e 100644 --- a/src/tasks/Crossgen2Tasks/ResolveReadyToRunCompilers.cs +++ b/src/tasks/Crossgen2Tasks/ResolveReadyToRunCompilers.cs @@ -146,8 +146,8 @@ private bool ValidateCrossgen2Support() // Normalize target OS for crossgen invocation string targetOS = (_targetPlatform == "win") ? "windows" : - // Map linux-{ musl,bionic,etc.} to linux - _targetPlatform.StartsWith("linux-", StringComparison.Ordinal) ? "linux" : + // Map linux-{ musl,bionic,etc.} and android to linux + (_targetPlatform.StartsWith("linux-", StringComparison.Ordinal) || (_targetPlatform == "android")) ? "linux" : _targetPlatform; // In .NET 5 Crossgen2 supported only the following host->target compilation scenarios: