Skip to content

Commit e040a28

Browse files
committed
NativeAOT detection support
1 parent 446ad65 commit e040a28

File tree

3 files changed

+114
-6
lines changed

3 files changed

+114
-6
lines changed

tools/apput/src/Native/SharedLibrary.cs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,23 @@ protected static bool IsSupportedELFSharedLibrary (Stream stream, string? descri
185185
}
186186
}
187187

188+
public bool HasSection (string name, SectionType type = SectionType.Null)
189+
{
190+
Log.Debug ($"Checking for section '{name}' with type {type} in library '{libraryName}'");
191+
if (!elf.TryGetSection (name, out ISection? section)) {
192+
Log.Debug ("Section not found");
193+
return false;
194+
}
195+
196+
if (type == SectionType.Null) {
197+
Log.Debug ("Section present, type check not requested");
198+
return true;
199+
}
200+
201+
Log.Debug ($"Section present, type {section.Type}");
202+
return section.Type == type;
203+
}
204+
188205
protected virtual void Dispose (bool disposing)
189206
{
190207
if (disposed) {

tools/apput/src/Package/ApplicationPackage.cs

Lines changed: 96 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using System.IO.Compression;
55
using System.Linq;
66

7+
using ELFSharp.ELF.Sections;
78
using Xamarin.Android.Tasks;
89
using Xamarin.Android.Tools;
910

@@ -32,6 +33,14 @@ public abstract class ApplicationPackage : IAspect
3233
"META-INF/ANDROIDD.RSA",
3334
};
3435

36+
readonly static List<(string sectionName, SectionType type)> NativeAotSections = new () {
37+
("__managedcode", SectionType.ProgBits),
38+
(".dotnet_eh_table", SectionType.ProgBits),
39+
("__unbox", SectionType.ProgBits),
40+
("__modules", SectionType.ProgBits),
41+
(".hydrated", SectionType.NoBits),
42+
};
43+
3544
public static string AspectName { get; } = "Application package";
3645

3746
public abstract string PackageFormat { get; }
@@ -112,6 +121,19 @@ void TryDetectArchitectures ()
112121

113122
void TryDetectRuntime ()
114123
{
124+
try {
125+
Runtime = GetRuntimeMaybe ();
126+
} catch (Exception ex) {
127+
Log.Debug ("Exception caught while detecting runtime.", ex);
128+
Runtime = ApplicationRuntime.Unknown;
129+
}
130+
131+
Log.Debug ($"Detected runtime: {Runtime}");
132+
}
133+
134+
ApplicationRuntime GetRuntimeMaybe ()
135+
{
136+
Log.Debug ("Trying to detect runtime");
115137
ApplicationRuntime runtime = ApplicationRuntime.Unknown;
116138
string runtimePath;
117139
foreach (AndroidTargetArch arch in Architectures) {
@@ -129,17 +151,85 @@ void TryDetectRuntime ()
129151
}
130152

131153
if (runtime != ApplicationRuntime.Unknown || Architectures.Count == 0) {
132-
Log.Debug ($"Detected runtime: {runtime}");
133-
return;
154+
return runtime;
134155
}
135156

136157
runtimePath = GetNativeLibFile (Architectures[0], "libmonodroid.so");
137-
if (!HasEntry (Zip, runtimePath)) {
138-
return;
158+
if (HasEntry (Zip, runtimePath)) {
159+
Log.Debug ("Unknown runtime. libmonodroid.so present but no CoreCLR or MonoVM libraries found.");
160+
return ApplicationRuntime.Unknown;
161+
}
162+
163+
// TODO: it might be statically linked CoreCLR runtime or a NativeAOT application.
164+
// Need to check for presence of some public symbols to verify that.
165+
if (TryDetectNativeAotRuntime ()) {
166+
return ApplicationRuntime.NativeAOT;
167+
}
168+
169+
return ApplicationRuntime.Unknown;
170+
}
171+
172+
bool TryDetectNativeAotRuntime ()
173+
{
174+
Log.Debug ("Probing for NativeAOT runtime");
175+
foreach (AndroidTargetArch arch in Architectures) {
176+
string libDir = GetNativeLibDir (arch);
177+
178+
foreach (ZipArchiveEntry? entry in Zip.Entries) {
179+
if (entry == null) {
180+
continue;
181+
}
182+
183+
// See if it's in the right directory...
184+
if (!entry.FullName.StartsWith (libDir, StringComparison.Ordinal)) {
185+
continue;
186+
}
187+
188+
// ...and that it's a shared library...
189+
if (!entry.FullName.EndsWith (".so", StringComparison.Ordinal)) {
190+
continue;
191+
}
192+
193+
Log.Debug ($"Considering {entry.FullName}");
194+
// ...and that it has NativeAOT markers
195+
if (!SharedLibraryIsNativeAOT (entry)) {
196+
continue;
197+
}
198+
199+
Log.Debug ("Found NativeAOT shared library");
200+
// Yep, got it. Just one hit is enough, no need to check all the architectures
201+
return true;
202+
}
203+
}
204+
205+
return false;
206+
}
207+
208+
bool SharedLibraryIsNativeAOT (ZipArchiveEntry entry)
209+
{
210+
Stream? stream = TryGetEntryStream (entry.FullName);
211+
if (stream == null) {
212+
return false;
213+
}
214+
215+
IAspectState aspectState = SharedLibrary.ProbeAspect (stream, entry.FullName);
216+
if (!aspectState.Success) {
217+
return false;
218+
}
219+
220+
var dso = SharedLibrary.LoadAspect (stream, aspectState, entry.FullName) as SharedLibrary;
221+
if (dso == null) {
222+
throw new InvalidOperationException ("Internal error: unexpected SharedLibrary load result.");
223+
}
224+
225+
// Just one match should be enough
226+
foreach (var naotSection in NativeAotSections) {
227+
if (dso.HasSection (naotSection.sectionName, naotSection.type)) {
228+
return true;
229+
}
139230
}
140231

141-
// TODO: it might be statically linked CoreCLR runtime. Need to check for presence of
142-
// some public symbols to verify that.
232+
return false;
143233
}
144234

145235
void TryLoadXamarinAppLibraries ()

tools/apput/src/Package/ApplicationRuntime.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,5 @@ public enum ApplicationRuntime
66
MonoVM,
77
CoreCLR,
88
StaticCoreCLR,
9+
NativeAOT,
910
}

0 commit comments

Comments
 (0)