AssemblyLoader should assist in loading all assemblies 88/105788/1
authorPawel Andruszkiewicz <p.andruszkie@samsung.com>
Fri, 9 Dec 2016 07:52:45 +0000 (08:52 +0100)
committerJongHeon Choi <j-h.choi@samsung.com>
Mon, 19 Dec 2016 12:03:09 +0000 (21:03 +0900)
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 <p.andruszkie@samsung.com>
Tizen.Runtime/Tizen.Runtime.Coreclr/AssemblyLoader.cs
Tizen.Runtime/Tizen.Runtime.Coreclr/AssemblyManager.cs

index cbb00958d32cefa226bdc0df9e4f247592f0aef6..35a8ddf567af44217039ca99403e3a7f7d3a451e 100755 (executable)
@@ -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<string> _dllDirectories = new SortedSet<string>();
         private SortedSet<string> _nativeDirectories = new SortedSet<string>();
 
+        private HashSet<FileInfo> _dllCache = new HashSet<FileInfo>();
+
+        public AssemblyLoader()
+        {
+            AssemblyLoadContext.Default.Resolving += OnResolving;
+        }
+
         public IEnumerable<string> 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);
+        }
     }
 }
index 52297a179429fea8b9f3caeab47ba5d0835b537b..de0b293fda9afc414dc0410ed9917f388476148f 100644 (file)
@@ -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)
             {