From 095697508a12bc9c471e096fdbd0a2e2b0b8f458 Mon Sep 17 00:00:00 2001 From: Pawel Andruszkiewicz Date: Fri, 9 Dec 2016 08:52:45 +0100 Subject: [PATCH] AssemblyLoader should assist in loading all assemblies The Resolving event from the AssemblyLoadContext is invoked each time it fails to load an assembly. The default AssemblyLoadContext is used internally i.e. when Assembly.Load() or Type.GetType(string) methods are called. Registering for the Resolving event from the default AssemblyLoadContext helps handling the unresolved assemblies and fixes XAML-related issues in Xamarin. TASK=TNET-136 TASK=TCAPI-1863 Change-Id: I0f5f4c2925829eac448a6184a3e19dbde5c1dfc0 Signed-off-by: Pawel Andruszkiewicz --- .../Tizen.Runtime.Coreclr/AssemblyLoader.cs | 89 +++++++++++++++------- .../Tizen.Runtime.Coreclr/AssemblyManager.cs | 24 ++---- 2 files changed, 69 insertions(+), 44 deletions(-) diff --git a/Tizen.Runtime/Tizen.Runtime.Coreclr/AssemblyLoader.cs b/Tizen.Runtime/Tizen.Runtime.Coreclr/AssemblyLoader.cs index cbb0095..35a8ddf 100755 --- a/Tizen.Runtime/Tizen.Runtime.Coreclr/AssemblyLoader.cs +++ b/Tizen.Runtime/Tizen.Runtime.Coreclr/AssemblyLoader.cs @@ -16,6 +16,7 @@ using System; using System.IO; +using System.Linq; using System.Reflection; using System.Runtime.Loader; using System.Collections.Generic; @@ -24,9 +25,24 @@ namespace Tizen.Runtime.Coreclr { public class AssemblyLoader : AssemblyLoadContext { + private const string NativeAssemblyInfix = ".ni"; + + private const string DllAssemblySuffix = ".dll"; + + private const string NativeDllAssemblySuffix = NativeAssemblyInfix + DllAssemblySuffix; + + private static readonly string[] s_suffixes = new string[] { NativeDllAssemblySuffix, DllAssemblySuffix }; + private SortedSet _dllDirectories = new SortedSet(); private SortedSet _nativeDirectories = new SortedSet(); + private HashSet _dllCache = new HashSet(); + + public AssemblyLoader() + { + AssemblyLoadContext.Default.Resolving += OnResolving; + } + public IEnumerable DllDirectories { get { return _dllDirectories; } @@ -43,6 +59,16 @@ namespace Tizen.Runtime.Coreclr { _dllDirectories.Add(directory); _nativeDirectories.Add(directory); + + foreach (var file in Directory.GetFiles(directory)) + { + var info = new FileInfo(file); + + if (info.Extension == DllAssemblySuffix) + { + _dllCache.Add(info); + } + } } } @@ -50,39 +76,30 @@ namespace Tizen.Runtime.Coreclr { _dllDirectories.Remove(directory); _nativeDirectories.Remove(directory); + + _dllCache.RemoveWhere(x => x.DirectoryName == directory); } - protected override Assembly Load(AssemblyName assemblyName) + public Assembly LoadFromPath(string path) { - Assembly asm = null; - - try + if (0 == string.Compare(path, // strA + path.Length - NativeDllAssemblySuffix.Length, // indexA + NativeAssemblyInfix, // strB + 0, // indexB + NativeAssemblyInfix.Length, // length + StringComparison.OrdinalIgnoreCase)) // options { - //asm = AssemblyLoadContext.Default.Load(assemblyName); - asm = AssemblyLoadContext.Default.LoadFromAssemblyName(assemblyName); + return LoadFromNativeImagePath(path, null); } - catch (Exception ex) - when (ex is FileNotFoundException || - ex is BadImageFormatException || - ex is FileLoadException) + else { - foreach (string dir in DllDirectories) - { - FileInfo f = new FileInfo(Path.Combine(dir, $"{assemblyName.Name}.ni.dll")); - if (File.Exists(f.FullName)) - { - asm = LoadFromNativeImagePath(f.FullName, null); - break; - } - f = new FileInfo(Path.Combine(dir, $"{assemblyName.Name}.dll")); - if (File.Exists(f.FullName)) - { - asm = LoadFromAssemblyPath(f.FullName); - break; - } - } + return LoadFromAssemblyPath(path); } - return asm; + } + + protected override Assembly Load(AssemblyName assemblyName) + { + return Resolve(assemblyName); } protected override IntPtr LoadUnmanagedDll(string unmanagedDllName) @@ -103,5 +120,25 @@ namespace Tizen.Runtime.Coreclr return native; } + + private Assembly Resolve(AssemblyName assemblyName) + { + foreach (string suffix in s_suffixes) + { + var info = _dllCache.FirstOrDefault(x => x.Name == assemblyName.Name + suffix); + + if (info != null) + { + return LoadFromPath(info.FullName); + } + } + + return null; + } + + private Assembly OnResolving(AssemblyLoadContext context, AssemblyName assemblyName) + { + return Resolve(assemblyName); + } } } diff --git a/Tizen.Runtime/Tizen.Runtime.Coreclr/AssemblyManager.cs b/Tizen.Runtime/Tizen.Runtime.Coreclr/AssemblyManager.cs index 52297a1..de0b293 100644 --- a/Tizen.Runtime/Tizen.Runtime.Coreclr/AssemblyManager.cs +++ b/Tizen.Runtime/Tizen.Runtime.Coreclr/AssemblyManager.cs @@ -146,15 +146,7 @@ namespace Tizen.Runtime.Coreclr ALog.Debug($"preload dll : {s}"); try { - Assembly asm = null; - if (s.EndsWith(".ni.dll", StringComparison.CurrentCultureIgnoreCase)) - { - asm = CurrentAssemblyLoaderContext.LoadFromNativeImagePath(s, null); - } - else - { - asm = CurrentAssemblyLoaderContext.LoadFromAssemblyPath(s); - } + Assembly asm = CurrentAssemblyLoaderContext.LoadFromPath(s); // this works strange, vm can't load types except loaded in here. // so user code spit out not found exception. @@ -195,20 +187,16 @@ namespace Tizen.Runtime.Coreclr FileInfo f = new FileInfo(dllPath); if (File.Exists(f.FullName)) { - Assembly asm = null; - if (0 == string.Compare(f.FullName, f.FullName.Length - 7, ".ni", 0, 3, StringComparison.OrdinalIgnoreCase)) - { - asm = CurrentAssemblyLoaderContext.LoadFromNativeImagePath(f.FullName, null); - } - else - { - asm = CurrentAssemblyLoaderContext.LoadFromAssemblyPath(f.FullName); - } + Assembly asm = CurrentAssemblyLoaderContext.LoadFromPath(f.FullName); if (asm == null) throw new FileNotFoundException($"{f.FullName} is not found"); if (asm.EntryPoint == null) throw new ArgumentException($"{f.FullName} did not have EntryPoint"); asm.EntryPoint.Invoke(null, new object[]{argv}); } + else + { + ALog.Debug($"Requested file does not exist: {dllPath}"); + } } catch (Exception e) { -- 2.7.4