Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
660fb33
[WIP] Build lib{c,m} stubs
grendello Oct 19, 2022
86c9dcf
Works locally, let's see
grendello Oct 20, 2022
8a3b808
Quote spaces in `lib{c,m}.so` paths and add a test
grendello Oct 20, 2022
5ca26c7
Package library stubs for all platforms
grendello Oct 21, 2022
6b00842
Spaces are rather important in command-line arguments
grendello Oct 21, 2022
25a1bd6
Merge branch 'main' into no-ndk-lib-stubs
grendello Oct 21, 2022
fbc4cf4
Those spaces are REALLY important, duh
grendello Oct 21, 2022
8d81ccb
Merge branch 'main' into no-ndk-lib-stubs
grendello Oct 26, 2022
1bea16c
Let's see if tests on Windows can find the stubs now
grendello Oct 26, 2022
63db768
Yet another attempt at quoting for classic Mono
grendello Oct 26, 2022
3dab27d
Try quoting the entire `ld-flags` value
grendello Oct 26, 2022
33e6610
Let's try this change from @peterc
grendello Oct 26, 2022
ffd8e43
Merge branch 'main' into no-ndk-lib-stubs
grendello Oct 27, 2022
edea1e9
Don't quote `ld-flags` value
grendello Oct 27, 2022
057d2f9
Use the stubs whenever not using Android NDK
grendello Oct 27, 2022
f8b82c1
Enable LLVM usage in the libc/libm reference test
grendello Oct 27, 2022
79421d3
Don't quote spaces
grendello Oct 27, 2022
523a2bb
Close yer parentheses, fool
grendello Oct 27, 2022
3266732
Let's put ld-flags last
grendello Oct 27, 2022
c121ad4
Merge branch 'main' into no-ndk-lib-stubs
grendello Nov 4, 2022
976f8c2
Merge branch 'main' into no-ndk-lib-stubs
grendello Nov 7, 2022
e8b9e61
Update RunWithLLVMEnabled() to verify that no .so files failed to load
jonpryor Nov 21, 2022
8d4672d
Merge branch 'main' into no-ndk-lib-stubs
grendello Feb 9, 2023
5be3d8b
Merge branch 'main' into no-ndk-lib-stubs
grendello Feb 10, 2023
2b53bd8
Merge branch 'main' into no-ndk-lib-stubs
grendello Feb 17, 2023
3b2cb45
Merge branch 'main' into no-ndk-lib-stubs
grendello Feb 22, 2023
3155aca
Merge branch 'main' into no-ndk-lib-stubs
grendello Feb 24, 2023
64e5fb6
Merge branch 'main' into no-ndk-lib-stubs
grendello Feb 24, 2023
8e6f958
Merge branch 'main' into no-ndk-lib-stubs
grendello Mar 6, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions build-tools/installers/create-installers.targets
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,14 @@
<_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)K4os.Compression.LZ4.dll" />
<_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)ELFSharp.dll" />
<_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)ManifestOverlays\Timing.xml" />
<_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)libstubs\android-arm64\libc.so" />
<_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)libstubs\android-arm64\libm.so" />
<_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)libstubs\android-arm\libc.so" />
<_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)libstubs\android-arm\libm.so" />
<_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)libstubs\android-x64\libc.so" />
<_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)libstubs\android-x64\libm.so" />
<_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)libstubs\android-x86\libc.so" />
<_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)libstubs\android-x86\libm.so" />
</ItemGroup>
<ItemGroup>
<_MSBuildTargetsSrcFiles Include="$(MSBuildTargetsSrcDir)\Xamarin.Android.AvailableItems.targets" />
Expand Down
7 changes: 4 additions & 3 deletions src/Xamarin.Android.Build.Tasks/Tasks/Aot.cs
Original file line number Diff line number Diff line change
Expand Up @@ -169,9 +169,6 @@ IEnumerable<Config> GetAotConfigs (NdkTools ndk)
if (!string.IsNullOrEmpty (LdName)) {
aotOptions.Add ($"ld-name={LdName}");
}
if (!string.IsNullOrEmpty (LdFlags)) {
aotOptions.Add ($"ld-flags={LdFlags}");
}

// We don't check whether any mode option was added via `AotAdditionalArguments`, the `AndroidAotMode` property should always win here.
// Modes not supported by us directly can be set by setting `AndroidAotMode` to "normal" and adding the desired mode name to the
Expand All @@ -186,6 +183,10 @@ IEnumerable<Config> GetAotConfigs (NdkTools ndk)
break;
}

if (!string.IsNullOrEmpty (LdFlags)) {
aotOptions.Add ($"ld-flags={LdFlags}");
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we also want to move the ld-name arg down here? I see there is a comment above about making sure both are always passed last.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure, to be honest. ld-name is an argument which takes a simple value which doesn't appear to confuse the AOT parser. I think I'd leave it where it is, especially that everything seems to have worked fine after the ld-flags repositioning.

// we need to quote the entire --aot arguments here to make sure it is parsed
// on windows as one argument. Otherwise it will be split up into multiple
// values, which wont work.
Expand Down
60 changes: 46 additions & 14 deletions src/Xamarin.Android.Build.Tasks/Tasks/GetAotArguments.cs
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,7 @@ string GetLdFlags (NdkTools ndk, AndroidTargetArch arch, int level, string toolP
{
var toolchainPath = toolPrefix.Substring (0, toolPrefix.LastIndexOf (Path.DirectorySeparatorChar));
var ldFlags = new StringBuilder ();
var libs = new List<string> ();
if (UseAndroidNdk && EnableLLVM) {
string androidLibPath = string.Empty;
try {
Expand All @@ -273,7 +274,6 @@ string GetLdFlags (NdkTools ndk, AndroidTargetArch arch, int level, string toolP
} else
toolchainLibDir = GetNdkToolchainLibraryDir (ndk, toolchainPath);

var libs = new List<string> ();
if (ndk.UsesClang) {
if (!String.IsNullOrEmpty (toolchainLibDir)) {
libs.Add ($"-L{toolchainLibDir.TrimEnd ('\\')}");
Expand All @@ -292,24 +292,36 @@ string GetLdFlags (NdkTools ndk, AndroidTargetArch arch, int level, string toolP
}
libs.Add (Path.Combine (androidLibPath, "libc.so"));
libs.Add (Path.Combine (androidLibPath, "libm.so"));
} else if (!UseAndroidNdk && EnableLLVM) {
// We need to link against libc and libm, but since NDK is not in use, the linker won't be able to find the actual Android libraries.
// Therefore, we will use their stubs to satisfy the linker. At runtime they will, of course, use the actual Android libraries.
string relPath = Path.Combine ("..", "..");
if (!OS.IsWindows) {
// the `binutils` directory is one level down (${OS}/binutils) than the Windows one
relPath = Path.Combine (relPath, "..");
}
string libstubsPath = Path.GetFullPath (Path.Combine (AndroidBinUtilsDirectory, relPath, "libstubs", ArchToRid (arch)));
libs.Add (Path.Combine (libstubsPath, "libc.so"));
libs.Add (Path.Combine (libstubsPath, "libm.so"));
}

if (libs.Count > 0) {
ldFlags.Append ($"\\\"{string.Join ("\\\";\\\"", libs)}\\\"");
} else {
}

//
// This flag is needed for Mono AOT to work correctly with the LLVM 14 `lld` linker due to the following change:
//
// The AArch64 port now supports adrp+ldr and adrp+add optimizations. --no-relax can suppress the optimization.
//
// Without the flag, `lld` will modify AOT-generated code in a way that the Mono runtime doesn't support. Until
// the runtime issue is fixed, we need to pass this flag then.
//
if (!UseAndroidNdk) {
if (ldFlags.Length > 0) {
ldFlags.Append (' ');
}

//
// This flag is needed for Mono AOT to work correctly with the LLVM 14 `lld` linker due to the following change:
//
// The AArch64 port now supports adrp+ldr and adrp+add optimizations. --no-relax can suppress the optimization.
//
// Without the flag, `lld` will modify AOT-generated code in a way that the Mono runtime doesn't support. Until
// the runtime issue is fixed, we need to pass this flag then.
//
if (!UseAndroidNdk) {
ldFlags.Append ("--no-relax");
}
ldFlags.Append ("--no-relax");
}

if (StripLibraries) {
Expand All @@ -320,6 +332,26 @@ string GetLdFlags (NdkTools ndk, AndroidTargetArch arch, int level, string toolP
}

return ldFlags.ToString ();

string ArchToRid (AndroidTargetArch arch)
{
switch (arch) {
case AndroidTargetArch.Arm64:
return "android-arm64";

case AndroidTargetArch.Arm:
return "android-arm";

case AndroidTargetArch.X86:
return "android-x86";

case AndroidTargetArch.X86_64:
return "android-x64";

default:
throw new InvalidOperationException ($"Internal error: unsupported ABI '{arch}'");
}
}
}

static string GetNdkToolchainLibraryDir (NdkTools ndk, string binDir, string archDir = null)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,42 @@ public void CheckMonoComponentsMask (bool enableProfiler, bool useInterpreter, b
}
}

[Test]
public void CheckWhetherLibcAndLibmAreReferencedInAOTLibraries ()
{
var proj = new XamarinAndroidApplicationProject {
IsRelease = true,
EmbedAssembliesIntoApk = true,
AotAssemblies = true,
};
proj.SetProperty ("EnableLLVM", "True");

var abis = new [] { "arm64-v8a", "x86_64" };
proj.SetAndroidSupportedAbis (abis);

var libPaths = new List<string> ();
if (Builder.UseDotNet) {
libPaths.Add (Path.Combine ("android-arm64", "aot", "Mono.Android.dll.so"));
libPaths.Add (Path.Combine ("android-x64", "aot", "Mono.Android.dll.so"));
} else {
libPaths.Add (Path.Combine ("aot", "arm64-v8a", "libaot-Mono.Android.dll.so"));
libPaths.Add (Path.Combine ("aot", "x86_64", "libaot-Mono.Android.dll.so"));
}

using (var b = CreateApkBuilder ()) {
Assert.IsTrue (b.Build (proj), "Build should have succeeded.");
string objPath = Path.Combine (Root, b.ProjectDirectory, proj.IntermediateOutputPath);

foreach (string libPath in libPaths) {
string lib = Path.Combine (objPath, libPath);

Assert.IsTrue (File.Exists (lib), $"Library {lib} should exist on disk");
Assert.IsTrue (ELFHelper.ReferencesLibrary (lib, "libc.so"), $"Library {lib} should reference libc.so");
Assert.IsTrue (ELFHelper.ReferencesLibrary (lib, "libm.so"), $"Library {lib} should reference libm.so");
}
}
}

static object [] CheckAssemblyCountsSource = new object [] {
new object[] {
/*isRelease*/ false,
Expand Down
40 changes: 40 additions & 0 deletions src/Xamarin.Android.Build.Tasks/Utilities/ELFHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,47 @@ public static bool IsEmptyAOTLibrary (TaskLoggingHelper log, string path)
log.LogWarningFromException (ex, showStackTrace: true);
return false;
}
}

public static bool ReferencesLibrary (string libraryPath, string referencedLibraryName)
{
if (String.IsNullOrEmpty (libraryPath) || !File.Exists (libraryPath)) {
return false;
}

IELF elf = ELFReader.Load (libraryPath);
var dynstr = GetSection (elf, ".dynstr") as IStringTable;
if (dynstr == null) {
return false;
}

foreach (IDynamicSection section in elf.GetSections<IDynamicSection> ()) {
foreach (IDynamicEntry entry in section.Entries) {
if (IsLibraryReference (dynstr, entry, referencedLibraryName)) {
return true;
}
}
}

return false;
}

static bool IsLibraryReference (IStringTable stringTable, IDynamicEntry dynEntry, string referencedLibraryName)
{
if (dynEntry.Tag != DynamicTag.Needed) {
return false;
}

ulong index;
if (dynEntry is DynamicEntry<ulong> entry64) {
index = entry64.Value;
} else if (dynEntry is DynamicEntry<uint> entry32) {
index = (ulong)entry32.Value;
} else {
return false;
}

return String.Compare (referencedLibraryName, stringTable[(long)index], StringComparison.Ordinal) == 0;
}

static bool IsEmptyAOTLibrary (TaskLoggingHelper log, string path, IELF elf)
Expand Down
59 changes: 59 additions & 0 deletions src/monodroid/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -427,6 +427,7 @@ endif()
if(ANDROID)
if(ENABLE_NET)
set(XA_LIBRARY_OUTPUT_DIRECTORY "${XA_LIB_TOP_DIR}/lib/${ANDROID_RID}")
set(XA_LIBRARY_STUBS_OUTPUT_DIRECTORY "${XA_LIB_TOP_DIR}/libstubs/${ANDROID_RID}")
link_directories("${NET_RUNTIME_DIR}/native")
else()
set(XA_LIBRARY_OUTPUT_DIRECTORY "${XA_LIB_TOP_DIR}/lib/${ANDROID_ABI}")
Expand Down Expand Up @@ -570,6 +571,10 @@ set(XAMARIN_DEBUG_APP_HELPER_SOURCES
${SOURCES_DIR}/shared-constants.cc
)

set(XAMARIN_STUB_LIB_SOURCES
libstub/stub.cc
)

# Build
configure_file(jni/host-config.h.in ${CMAKE_CURRENT_BINARY_DIR}/include/host-config.h)

Expand Down Expand Up @@ -716,3 +721,57 @@ target_link_libraries(
${XAMARIN_MONO_ANDROID_LIB}
${LINK_LIBS} xamarin-app
)

if(ANDROID AND ENABLE_NET)
add_library(
c
SHARED ${XAMARIN_STUB_LIB_SOURCES}
)

target_compile_definitions(
c
PRIVATE STUB_LIB_NAME=libc
)

target_compile_options(
c
PRIVATE -nostdlib
)

target_link_options(
c
PRIVATE -nostdlib
)

set_target_properties(
c
PROPERTIES
LIBRARY_OUTPUT_DIRECTORY "${XA_LIBRARY_STUBS_OUTPUT_DIRECTORY}"
)

add_library(
m
SHARED ${XAMARIN_STUB_LIB_SOURCES}
)

target_compile_definitions(
m
PRIVATE STUB_LIB_NAME=libm
)

target_compile_options(
m
PRIVATE -nostdlib
)

target_link_options(
m
PRIVATE -nostdlib
)

set_target_properties(
m
PROPERTIES
LIBRARY_OUTPUT_DIRECTORY "${XA_LIBRARY_STUBS_OUTPUT_DIRECTORY}"
)
endif()
8 changes: 8 additions & 0 deletions src/monodroid/libstub/stub.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#if !defined (STUB_LIB_NAME)
#error STUB_LIB_NAME must be defined on command line
#endif

void STUB_LIB_NAME ()
{
// no-op
}
26 changes: 24 additions & 2 deletions tests/MSBuildDeviceIntegration/Tests/InstallAndRunTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -749,8 +749,30 @@ public void RunWithLLVMEnabled ()
else
AdbStartActivity ($"{proj.PackageName}/{proj.JavaPackageName}.MainActivity");

Assert.IsTrue (WaitForActivityToStart (proj.PackageName, "MainActivity",
Path.Combine (Root, builder.ProjectDirectory, "startup-logcat.log")));
var activityNamespace = proj.PackageName;
var activityName = "MainActivity";
var logcatFilePath = Path.Combine (Root, builder.ProjectDirectory, "startup-logcat.log");
var failedToLoad = new List<string> ();
bool appLaunched = MonitorAdbLogcat ((line) => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@grendello, @dellis1972: how does this updated test look for verifying that .so files were all loaded successfully?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@grendello, @dellis1972 : my attempted unit test change failed. Is that because things aren't working properly, or because the test is looking for the wrong thing?

LLVM .so files not loaded:
11-21 23:05:25.104 10192 10192 I monodroid-assembly: Failed to load shared library '/data/app/com.xamarin.runwithinterpreterenabled-EBknjyBcFiejLCycXre3mw==/split_config.x86_64.apk!/lib/x86_64/UnnamedProject.dll.so'. dlopen failed: library "/data/app/com.xamarin.runwithinterpreterenabled-EBknjyBcFiejLCycXre3mw==/split_config.x86_64.apk!/lib/x86_64/UnnamedProject.dll.so" not found
11-21 23:05:25.105 10192 10192 I monodroid-assembly: Failed to load shared library 'UnnamedProject.dll.so'. dlopen failed: library "UnnamedProject.dll.so" not found
11-21 23:05:25.106 10192 10192 I monodroid-assembly: Failed to load shared library '/data/app/com.xamarin.runwithinterpreterenabled-EBknjyBcFiejLCycXre3mw==/split_config.x86_64.apk!/lib/x86_64/Mono.Android.dll.so'. dlopen failed: library "/data/app/com.xamarin.runwithinterpreterenabled-EBknjyBcFiejLCycXre3mw==/split_config.x86_64.apk!/lib/x86_64/Mono.Android.dll.so" not found
11-21 23:05:25.106 10192 10192 I monodroid-assembly: Failed to load shared library 'Mono.Android.dll.so'. dlopen failed: library "Mono.Android.dll.so" not found
11-21 23:05:25.107 10192 10192 I monodroid-assembly: Failed to load shared library '/data/app/com.xamarin.runwithinterpreterenabled-EBknjyBcFiejLCycXre3mw==/split_config.x86_64.apk!/lib/x86_64/Java.Interop.dll.so'. dlopen failed: library "/data/app/com.xamarin.runwithinterpreterenabled-EBknjyBcFiejLCycXre3mw==/split_config.x86_64.apk!/lib/x86_64/Java.Interop.dll.so" not found
11-21 23:05:25.108 10192 10192 I monodroid-assembly: Failed to load shared library 'Java.Interop.dll.so'. dlopen failed: library "Java.Interop.dll.so" not found
11-21 23:05:25.116 10192 10192 I monodroid-assembly: Failed to load shared library '/data/app/com.xamarin.runwithinterpreterenabled-EBknjyBcFiejLCycXre3mw==/split_config.x86_64.apk!/lib/x86_64/Mono.Android.Runtime.dll.so'. dlopen failed: library "/data/app/com.xamarin.runwithinterpreterenabled-EBknjyBcFiejLCycXre3mw==/split_config.x86_64.apk!/lib/x86_64/Mono.Android.Runtime.dll.so" not found
11-21 23:05:25.116 10192 10192 I monodroid-assembly: Failed to load shared library 'Mono.Android.Runtime.dll.so'. dlopen failed: library "Mono.Android.Runtime.dll.so" not found
11-21 23:05:25.122 10192 10192 I monodroid-assembly: Failed to load shared library '/data/app/com.xamarin.runwithinterpreterenabled-EBknjyBcFiejLCycXre3mw==/split_config.x86_64.apk!/lib/x86_64/System.Runtime.dll.so'. dlopen failed: library "/data/app/com.xamarin.runwithinterpreterenabled-EBknjyBcFiejLCycXre3mw==/split_config.x86_64.apk!/lib/x86_64/System.Runtime.dll.so" not found
11-21 23:05:25.122 10192 10192 I monodroid-assembly: Failed to load shared library 'System.Runtime.dll.so'. dlopen failed: library "System.Runtime.dll.so" not found
11-21 23:05:25.585 10192 10192 I monodroid-assembly: Failed to load shared library '/data/app/com.xamarin.runwithinterpreterenabled-EBknjyBcFiejLCycXre3mw==/split_config.x86_64.apk!/lib/x86_64/System.Console.dll.so'. dlopen failed: library "/data/app/com.xamarin.runwithinterpreterenabled-EBknjyBcFiejLCycXre3mw==/split_config.x86_64.apk!/lib/x86_64/System.Console.dll.so" not found
11-21 23:05:25.585 10192 10192 I monodroid-assembly: Failed to load shared library 'System.Console.dll.so'. dlopen failed: library "System.Console.dll.so" not found
Expected: 0
But was:  12

My guess is that Failed to load shared library always appears, because not all assemblies are AOT'd. Which seems odd, as $(EnableLLVM)=true is set; shouldn't that AOT all of them?

Also, those names look weird, e.g. System.Runtime.dll.so can't be found. Shouldn't it be libaot-System.Runtime.dll.so?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lines ending with not found should be ignored, since it's perfectly fine that an AOT library wasn't packaged (e.g. if it was empty) or even created. However, testing for this properly would require finding a library that references one of the symbols in libc/libm and check if that library is loaded. However, I can't find any such library.

@jonathanpeppers originally found the problem in libaot-Mono.Android.dll.so:

so I was testing LLVM with the .NET 7 RC, and noticed it was really slow...
Looking at full logcat I get:
10-18 23:55:17.844 20389 20389 D monodroid-assembly: monodroid_dlopen: hash match found, DSO name is 'libaot-Mono.Android.dll.so'
10-18 23:55:17.844 20389 20389 I monodroid-assembly: Trying to load shared library '/data/app/~~4kGTzxWG6HKO7nzyg6ryBg==/com.companyname.hellomaui.old-h8Jlutcvf8Dzfpuuq1ouUA==/lib/arm64/libaot-Mono.Android.dll.so'
10-18 23:55:17.844 20389 20389 I monodroid-assembly: Failed to load shared library '/data/app/~~4kGTzxWG6HKO7nzyg6ryBg==/com.companyname.hellomaui.old-h8Jlutcvf8Dzfpuuq1ouUA==/lib/arm64/libaot-Mono.Android.dll.so'. dlopen failed: cannot locate symbol "memset" referenced by "/data/app/~~4kGTzxWG6HKO7nzyg6ryBg==/com.companyname.hellomaui.old-h8Jlutcvf8Dzfpuuq1ouUA==/lib/arm64/libaot-Mono.Android.dll.so"...

Do you have an idea of what went wrong there?
Basically none of the AOT images are loading

And indeed, when you look at symbols referenced by libaot-Mono.Android.dll.so from the apk (see the attached zip), you can see both the references and a text segment:

$ llvm-nm -CD libaot-Mono.Android.dll.so | head -10
0000000000048450 W gc.safepoint_poll
                 U memset
00000000000d89d0 D mono_aot_file_info
00000000000a9f80 T p_101_plt_Java_Net_Proxy_get_NoProxy_llvm
00000000000aa00c T p_108_plt_Android_Runtime_JNIEnv_FindClass_string_llvm
00000000000aa020 T p_109_plt_Android_Runtime_JNIEnv_GetMethodID_intptr_string_string_llvm
00000000000aa034 T p_110_plt_Android_Runtime_JNIEnv_DeleteGlobalRef_intptr_llvm
00000000000aa070 T p_113_plt_Android_Runtime_JNIEnv_CallObjectMethod_intptr_intptr_llvm
00000000000aa0d4 T p_118_plt_Java_Net_HttpURLConnection__ctor_intptr_Android_Runtime_JniHandleOwnership_llvm
00000000000aa0e8 T p_119_plt_Android_Runtime_XAPeerMembers__ctor_string_System_Type_llvm

However, Mono.Android.dll.so produced with XA/main has just the data mono_aot_file_info symbol:

$ llvm-nm -CD Mono.Android.dll.so | head -10
0000000000062840 D mono_aot_file_info

@jonathanpeppers's test was with one of the NET7 RC builds, so perhaps something has changed inbetween? Also with regard to library names?

libraries.zip

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With regards to names, I've just checked and we still rename the .so libraries to have the libaot prefix when packaging:

$ zipinfo com.microsoft.net6.helloandroid-Signed.apk | grep 'lib/arm64-v8a/.*Mono\.Android.*' | head 
-rwxr-xr-x  6.3 unx     4432 b- defX 22-Nov-22 09:08 lib/arm64-v8a/libaot-Mono.Android.Runtime.dll.so
-rwxr-xr-x  6.3 unx   208512 b- defX 22-Nov-22 09:08 lib/arm64-v8a/libaot-Mono.Android.dll.so

The reason you see the unprefixed names in error messages is that this is what MonoVM asks us to load, it isn't aware of the libaot prefix. The way it works now, is that we generate hash entries for various mutations of the library name at build time and then use the hash to look up the "real" (packaged) name of the shared library, but the name in the error message is what was originally requested by Mono.

Consider this fragment of the environment.arm64-v8a.ll file we generate:

@__DSOCacheEntry_name.1 = internal constant [27 x i8] c"libaot-Mono.Android.dll.so\00", align 1

; dso_cache
@dso_cache = local_unnamed_addr global [140 x %struct.DSOCacheEntry] [
        ; 0
        %struct.DSOCacheEntry {
                i64 120698629574877762, ; hash 0x1accec39cafe242, from name: Mono.Android
                i8 0, ; ignore
                i8* getelementptr inbounds ([27 x i8], [27 x i8]* @__DSOCacheEntry_name.1, i32 0, i32 0), ; name
                i8* null; handle
        },
        ; 54
        %struct.DSOCacheEntry {
                i64 8522025752637549819, ; hash 0x7644514538b12cfb, from name: aot-Mono.Android.dll.so
                i8 0, ; ignore
                i8* getelementptr inbounds ([27 x i8], [27 x i8]* @__DSOCacheEntry_name.1, i32 0, i32 0), ; name
                i8* null; handle
        }, 
        ; 61
        %struct.DSOCacheEntry {
                i64 8772604801161716260, ; hash 0x79be8d9660216224, from name: aot-Mono.Android
                i8 0, ; ignore
                i8* getelementptr inbounds ([27 x i8], [27 x i8]* @__DSOCacheEntry_name.1, i32 0, i32 0), ; name
                i8* null; handle
        }, 
        ; 115
        %struct.DSOCacheEntry {
                i64 15394198501530322172, ; hash 0xd5a32df9a590c4fc, from name: libaot-Mono.Android
                i8 0, ; ignore
                i8* getelementptr inbounds ([27 x i8], [27 x i8]* @__DSOCacheEntry_name.1, i32 0, i32 0), ; name
                i8* null; handle
        }, 
        ; 129
        %struct.DSOCacheEntry {
                i64 16768067971893542065, ; hash 0xe8b424faba51bcb1, from name: libaot-Mono.Android.dll.so
                i8 0, ; ignore
                i8* getelementptr inbounds ([27 x i8], [27 x i8]* @__DSOCacheEntry_name.1, i32 0, i32 0), ; name
                i8* null; handle
        }, 
        ; 131
        %struct.DSOCacheEntry {
                i64 17309541862275468045, ; hash 0xf037d89d25aecb0d, from name: Mono.Android.dll.so
                i8 0, ; ignore
                i8* getelementptr inbounds ([27 x i8], [27 x i8]* @__DSOCacheEntry_name.1, i32 0, i32 0), ; name
                i8* null; handle
        }, 
], align 8; end of 'dso_cache' array

Note that all of the entries map the various mutations of the name to the name that's actually in the package - the @__DSOCacheEntry_name.1 string. This speeds up look up, regardless of what name MonoVM passes to us but perhaps the error message should refer to the packaged name (although knowing what MonoVM requested is also valuable)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the test passing because $(AndroidNdkDirectory) is set and valid?

When I hit the original problem, I was building on Azure DevOps with an NDK in a non-standard location -- would be the same as not having an NDK installed at all.

I solved the problem by doing:

-p:AndroidNdkDirectory=$(ANDROID_NDK_HOME)

if (SeenFailedToLoad (line))
failedToLoad.Add (line);
return SeenActivityDisplayed (line);
}, logcatFilePath, timeout: 120);

Assert.IsTrue (appLaunched, "LLVM app did not launch");
Assert.AreEqual (0, failedToLoad.Count, $"LLVM .so files not loaded:\n{string.Join ("\n", failedToLoad)}");

bool SeenActivityDisplayed (string line)
{
var idx1 = line.IndexOf ("ActivityManager: Displayed", StringComparison.OrdinalIgnoreCase);
var idx2 = idx1 > 0 ? 0 : line.IndexOf ("ActivityTaskManager: Displayed", StringComparison.OrdinalIgnoreCase);
return (idx1 > 0 || idx2 > 0) && line.Contains (activityNamespace) && line.Contains (activityName);
}

bool SeenFailedToLoad (string line)
{
return line.Contains ("Failed to load shared library");
}
}

[Test]
Expand Down