44using System . IO . Compression ;
55using System . Linq ;
66
7+ using ELFSharp . ELF . Sections ;
78using Xamarin . Android . Tasks ;
89using 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 ( )
0 commit comments