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 cbb0095..35a8ddf 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 52297a1..de0b293 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)
             {