Skip to content

Commit a953d3f

Browse files
jonpryordellis1972
authored andcommitted
[Xamarin.Android.Build.Tasks] AOT+LLVM needs minSdkVersion (#795)
Fixes: https://bugzilla.xamarin.com/show_bug.cgi?id=58029 Scenario: Build a project with: * `$(Configuration)`=Release * `$(AotAssemblies)`=True * `$(EnableLLVM)`=True * `$(TargetFrameworkVersion)`=v7.1 (API-25) * `//uses-sdk/@android:minSdkVersion`=10 (in `AndroidManifest.xml`) * with Android NDK r12b or later * on particular hardware devices, e.g. a Nexus 5. Actual results: the app runs, but the AOT'd images aren't used: AOT: image 'Xamarin.Android.Support.v7.AppCompat.dll.so' not found: dlopen failed: cannot locate symbol "__aeabi_memset" referenced by "/data/app/com.companyname.App1-1/lib/arm/libaot-Xamarin.Android.Support.v7.AppCompat.dll.so"... The `__aeabi_memset` symbol can't be found, preventing e.g. `Xamarin.Android.Support.v7.AppCompat.dll.so` from being used. Meaning the app pays the build overhead and size penalty of AOT+LLVM, but doesn't get anything out of it; only the JIT is used. The [cause of the missing `__aeabi_memset` symbol][0] is that we're using the NDK paths which corresponds with `$(TargetFrameworkVersion)`, *not* the NDK paths which correspond with `//uses-sdk/@android:minSdkVersion`. Because of this, if you use the `.apk` on a platform which is >= `minSdkVersion` but less than `$(TargetFrameworkVersion)`, the AOT images won't be used. [0]: android/ndk#126 Fix this by updating the `<Aot/>` task to instead use the `//uses-sdk/@android:minSdkVersion` value. This ensures that we use NDK paths which correspond to the app's minimum supported API level, which should allow the AOT images to be loaded on downlevel devices.
1 parent b8dc732 commit a953d3f

File tree

3 files changed

+37
-2
lines changed

3 files changed

+37
-2
lines changed

src/Xamarin.Android.Build.Tasks/Tasks/Aot.cs

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,9 @@ public class Aot : AsyncTask
4141
[Required]
4242
public string AndroidApiLevel { get; set; }
4343

44+
[Required]
45+
public ITaskItem ManifestFile { get; set; }
46+
4447
[Required]
4548
public ITaskItem[] ResolvedAssemblies { get; set; }
4649

@@ -165,9 +168,22 @@ static bool ValidateAotConfiguration (TaskLoggingHelper log, AndroidTargetArch a
165168
return true;
166169
}
167170

168-
static int GetNdkApiLevel(string androidNdkPath, string androidApiLevel, AndroidTargetArch arch)
171+
int GetNdkApiLevel(string androidNdkPath, string androidApiLevel, AndroidTargetArch arch)
169172
{
170-
int level = int.Parse(androidApiLevel);
173+
var manifest = AndroidAppManifest.Load (ManifestFile.ItemSpec, MonoAndroidHelper.SupportedVersions);
174+
175+
int level;
176+
if (manifest.MinSdkVersion.HasValue) {
177+
level = manifest.MinSdkVersion.Value;
178+
}
179+
else if (int.TryParse (androidApiLevel, out level)) {
180+
// level already set
181+
}
182+
else {
183+
// Probably not ideal!
184+
level = MonoAndroidHelper.SupportedVersions.MaxStableVersion.ApiLevel;
185+
}
186+
171187
// Some Android API levels do not exist on the NDK level. Workaround this my mapping them to the
172188
// most appropriate API level that does exist.
173189
if (level == 6 || level == 7) level = 5;

src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest.cs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using System.IO;
33
using System.Linq;
44
using System.Text;
5+
using System.Text.RegularExpressions;
56
using System.Xml.Linq;
67
using Microsoft.Build.Framework;
78
using NUnit.Framework;
@@ -209,12 +210,29 @@ public void BuildAotApplication (string supportedAbis, bool enableLLVM, bool exp
209210
proj.SetProperty (KnownProperties.TargetFrameworkVersion, "v5.1");
210211
proj.SetProperty (KnownProperties.AndroidSupportedAbis, supportedAbis);
211212
proj.SetProperty ("EnableLLVM", enableLLVM.ToString ());
213+
if (enableLLVM) {
214+
// Set //uses-sdk/@android:minSdkVersion so that LLVM uses the right libc.so
215+
proj.AndroidManifest = $@"<?xml version=""1.0"" encoding=""utf-8""?>
216+
<manifest xmlns:android=""http://schemas.android.com/apk/res/android"" android:versionCode=""1"" android:versionName=""1.0"" package=""{proj.PackageName}"">
217+
<uses-sdk android:minSdkVersion=""10"" />
218+
<application android:label=""{proj.ProjectName}"">
219+
</application>
220+
</manifest>";
221+
}
212222
using (var b = CreateApkBuilder (path)) {
213223
b.ThrowOnBuildFailure = false;
214224
b.Verbosity = LoggerVerbosity.Diagnostic;
215225
Assert.AreEqual (expectedResult, b.Build (proj), "Build should have {0}.", expectedResult ? "succeeded" : "failed");
216226
if (!expectedResult)
217227
return;
228+
if (enableLLVM) {
229+
// LLVM passes a direct path to libc.so, and we need to use the libc.so
230+
// which corresponds to the *minimum* SDK version specified in AndroidManifest.xml
231+
// Since we overrode minSdkVersion=10, that means we should use libc.so from android-9.
232+
var rightLibc = new Regex (@"^\s*\[AOT\].*cross-.*--llvm.*,ld-flags=.*android-9.arch-.*.usr.lib.libc\.so", RegexOptions.Multiline);
233+
var m = rightLibc.Match (b.LastBuildOutput);
234+
Assert.IsTrue (m.Success, "AOT+LLVM should use libc.so from minSdkVersion!");
235+
}
218236
foreach (var abi in supportedAbis.Split (new char [] { ';' })) {
219237
var libapp = Path.Combine (Root, b.ProjectDirectory, proj.IntermediateOutputPath,
220238
"bundles", abi, "libmonodroid_bundle_app.so");

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2159,6 +2159,7 @@ because xbuild doesn't support framework reference assemblies.
21592159
AndroidAotMode="$(AndroidAotMode)"
21602160
AndroidNdkDirectory="$(_AndroidNdkDirectory)"
21612161
AndroidApiLevel="$(_AndroidApiLevel)"
2162+
ManifestFile="$(IntermediateOutputPath)android\AndroidManifest.xml"
21622163
SupportedAbis="$(_BuildTargetAbis)"
21632164
AndroidSequencePointsMode="$(_SequencePointsMode)"
21642165
AotAdditionalArguments="$(AndroidAotAdditionalArguments)"

0 commit comments

Comments
 (0)