Skip to content

Commit 0dd3d61

Browse files
committed
Work around an Android 9 dlopen bug on x86
Fixes: #4893 This commit fixes an issue in Android 9 (API 28) 32-bit (ONLY) dynamic loader issue where if the same library is loaded more than once, instead of returning a handle to the already loaded copy, `dlopen` will reinitialize the library thus resetting its state (BSS section is cleared, global instances of C++ classes are re-instantiated etc). When the library is reinitalized, however, our runtime is not - since the Java `Runtime.initialize`, which ends up in our native code, is *not* called because the library load is not part of the process startup, when `Runtime.initialize` is invoked. This in turn leads to situation when certain class members initialized in `Runtime.initialize` and assumed to be correct throughout the application life are, in fact, invalid and lead to crashes. In the instance of issue #4893, the problem was that the `MonodroidRuntime::Class_getName` field was not initialized to point to the `Java.Lang.Class.getName` Java method and that, in turn, led to Xamarin.Android not being able to look up Java types during application execution time. `libmonodroid.so` is reloaded whenever Mono tries to resolve an `__Internal` p/invoke (via a call to Xamarin.Android's `monodroid_dlopen` fallback handler) - these p/invokes are assumed to live in `libmonodroid` so we need to return a handle to it, so that Mono can subsequently use `dlsym` to look up the required symbol. Given the situation described in the previous paragraph, we need a way to not reload `libmonodroid` or do something else to avoid it being reinitialized. Since there's no portable way to check whether a DSO is already loaded we need to resort to "something else", implemented in this commit. We move all the functions used in `__Internal` p/invokes to a separate DSO which can be reloaded & reinitialized over and over again without shredding our global state. This is done by way of introducing a C++ interface class, `MonoAndroidExternalAPI` which is passed to the new DSO on load time, thus giving it a way to invoke all the necessary internal Xamarin.Android functions the `__Internal` p/invokes need in order to work as expected.
1 parent 5d0ff03 commit 0dd3d61

18 files changed

+645
-167
lines changed

build-tools/installers/create-installers.targets

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,7 @@
159159
<_MSBuildFiles Include="$(MSBuildSrcDir)\LayoutBinding.cs" />
160160
<_MSBuildFiles Include="@(AndroidSupportedTargetJitAbi->'$(MSBuildSrcDir)\lib\%(Identity)\libmono-android.debug.so')" Condition=" '$(PackageId)' != 'Microsoft.Android.Sdk' " />
161161
<_MSBuildFiles Include="@(AndroidSupportedTargetJitAbi->'$(MSBuildSrcDir)\lib\%(Identity)\libmono-android.release.so')" Condition=" '$(PackageId)' != 'Microsoft.Android.Sdk' " />
162+
<_MSBuildFiles Include="@(AndroidSupportedTargetJitAbi->'$(MSBuildSrcDir)\lib\%(Identity)\libmonodroid-mono-api.so')" Condition=" '$(PackageId)' != 'Microsoft.Android.Sdk' " />
162163
<_MSBuildFiles Include="@(AndroidSupportedTargetJitAbi->'$(MSBuildSrcDir)\lib\%(Identity)\libmono-btls-shared.so')" Condition=" '$(PackageId)' != 'Microsoft.Android.Sdk' " />
163164
<_MSBuildFiles Include="@(AndroidSupportedTargetJitAbi->'$(MSBuildSrcDir)\lib\%(Identity)\libmono-profiler-aot.so')" Condition=" '$(PackageId)' != 'Microsoft.Android.Sdk' " />
164165
<_MSBuildFiles Include="@(AndroidSupportedTargetJitAbi->'$(MSBuildSrcDir)\lib\%(Identity)\libmono-profiler-log.so')" Condition=" '$(PackageId)' != 'Microsoft.Android.Sdk' " />
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<?xml version="1.0" encoding="utf-8"?>
22
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="1.0" package="com.xamarin.android.helloworld">
33
<uses-sdk android:minSdkVersion="21" />
4-
<application android:allowBackup="true" android:icon="@mipmap/icon" android:label="@string/app_name">
4+
<application android:allowBackup="true" android:icon="@mipmap/icon" android:label="@string/app_name" android:extractNativeLibs="false">
55
</application>
66
</manifest>

src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1958,6 +1958,7 @@ because xbuild doesn't support framework reference assemblies.
19581958
<_AndroidNativeLibraryForFastDev Condition=" '$(_InstantRunEnabled)' == 'True' And '$(AndroidUseDebugRuntime)' == 'True' " Include="%(_TargetLibDir.Identity)\libxamarin-debug-app-helper.so" />
19591959
<FrameworkNativeLibrary Include="%(_TargetLibDir.Identity)\libmono-android.debug.so" Condition=" '$(AndroidIncludeDebugSymbols)' == 'True' " ArchiveFileName="libmonodroid.so" />
19601960
<FrameworkNativeLibrary Include="%(_TargetLibDir.Identity)\libmono-android.release.so" Condition=" '$(AndroidIncludeDebugSymbols)' != 'True' " ArchiveFileName="libmonodroid.so" />
1961+
<FrameworkNativeLibrary Include="%(_TargetLibInterpreterDir.Identity)\libmonodroid-mono-api.so" />
19611962
<FrameworkNativeLibrary Include="%(_TargetLibInterpreterDir.Identity)\libmono-btls-shared.so" />
19621963
<FrameworkNativeLibrary Include="%(_TargetLibInterpreterDir.Identity)\libmono-profiler-aot.so" Condition=" @(_EmbedProfilers->Count()) > 0 and (@(_EmbedProfilers->AnyHaveMetadataValue('Identity', 'aot')) or @(_EmbedProfilers->AnyHaveMetadataValue('Identity', 'all'))) " />
19631964
<FrameworkNativeLibrary Include="%(_TargetLibInterpreterDir.Identity)\libmono-profiler-log.so" Condition=" '$(AndroidIncludeDebugSymbols)' == 'True' or (@(_EmbedProfilers->Count()) > 0 and (@(_EmbedProfilers->AnyHaveMetadataValue('Identity', 'log')) or @(_EmbedProfilers->AnyHaveMetadataValue('Identity', 'all')))) " />

src/monodroid/CMakeLists.txt

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,8 @@ else()
220220
endif()
221221
endif()
222222

223+
string(STRIP "${EXTRA_LINKER_FLAGS}" EXTRA_LINKER_FLAGS)
224+
223225
if (ENABLE_TIMING)
224226
add_definitions("-DMONODROID_TIMING=1")
225227
endif()
@@ -277,11 +279,10 @@ set(MONODROID_SOURCES
277279
${SOURCES_DIR}/debug-constants.cc
278280
${SOURCES_DIR}/embedded-assemblies.cc
279281
${SOURCES_DIR}/embedded-assemblies-zip.cc
280-
${SOURCES_DIR}/external-api.cc
281282
${SOURCES_DIR}/globals.cc
282-
${SOURCES_DIR}/jni.c
283283
${SOURCES_DIR}/logger.cc
284284
${SOURCES_DIR}/monodroid-glue.cc
285+
${SOURCES_DIR}/monodroid-external-api.cc
285286
${SOURCES_DIR}/osbridge.cc
286287
${SOURCES_DIR}/shared-constants.cc
287288
${SOURCES_DIR}/timezones.cc
@@ -291,6 +292,12 @@ set(MONODROID_SOURCES
291292
${JAVA_INTEROP_SRC_PATH}/java-interop-util.cc
292293
)
293294

295+
set(MONODROID_MONO_API_SOURCES
296+
${SOURCES_DIR}/jni.c
297+
${SOURCES_DIR}/external-api.cc
298+
${JAVA_INTEROP_SRC_PATH}/java-interop-util.cc
299+
)
300+
294301
if(ENABLE_NDK)
295302
set(MONODROID_SOURCES
296303
${MONODROID_SOURCES}
@@ -306,6 +313,15 @@ if(UNIX)
306313
)
307314
endif()
308315

316+
add_library(monodroid-mono-api SHARED ${MONODROID_MONO_API_SOURCES})
317+
target_link_libraries(monodroid-mono-api ${EXTRA_LINKER_FLAGS})
318+
set_target_properties(
319+
monodroid-mono-api
320+
PROPERTIES
321+
COMPILE_FLAGS -fvisibility=default
322+
LINK_FLAGS -fvisibility=default
323+
)
324+
309325
set(XAMARIN_APP_STUB_SOURCES ${SOURCES_DIR}/application_dso_stub.cc)
310326
add_library(xamarin-app SHARED ${XAMARIN_APP_STUB_SOURCES})
311327
if (ENABLE_NDK)

src/monodroid/jni/cpu-arch-detect.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -225,7 +225,7 @@ get_running_on_cpu (unsigned short *running_on_cpu)
225225
*running_on_cpu = CPU_KIND_UNKNOWN;
226226
}
227227

228-
MONO_API void
228+
void
229229
_monodroid_detect_cpu_and_architecture (unsigned short *built_for_cpu, unsigned short *running_on_cpu, unsigned char *is64bit)
230230
{
231231
assert (built_for_cpu);

src/monodroid/jni/embedded-assemblies.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -597,7 +597,7 @@ EmbeddedAssemblies::md_mmap_apk_file (int fd, uint32_t offset, uint32_t size, co
597597
md_mmap_info file_info;
598598
md_mmap_info mmap_info;
599599

600-
size_t pageSize = static_cast<size_t>(monodroid_getpagesize());
600+
size_t pageSize = static_cast<size_t>(utils.monodroid_getpagesize ());
601601
uint32_t offsetFromPage = static_cast<uint32_t>(offset % pageSize);
602602
uint32_t offsetPage = offset - offsetFromPage;
603603
uint32_t offsetSize = size + offsetFromPage;

0 commit comments

Comments
 (0)