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