/* * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved * * Licensed under the Apache License, Version 2.0 (the License); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an AS IS BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ using System; using System.IO; using System.Reflection; using System.Runtime.Loader; using System.Linq; using System.Runtime.InteropServices; namespace Tizen.Runtime.Coreclr { public static class AssemblyManager { public static bool Launch( [In] string rootPath, [In] string path, [In] int argc, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex=2)] [In] string[] argv) { ALog.Debug($"Application Launch path : {path}"); try { DirectoryInfo bindir = new DirectoryInfo(Path.Combine(rootPath, "bin")); DirectoryInfo libdir = new DirectoryInfo(Path.Combine(rootPath, "lib")); if (Directory.Exists(bindir.FullName)) { CurrentAssemblyLoaderContext.AddSearchableDirectory(bindir.FullName); } if (Directory.Exists(libdir.FullName)) { CurrentAssemblyLoaderContext.AddSearchableDirectory(libdir.FullName); } Execute(path, argv); } catch(Exception e) { ALog.Debug("Exception in Launch()"); PrintException(e); return false; } return true; } public static void Prepared() { try { string preloadPath = ""; ICustomAttributeProvider assembly = typeof(AssemblyManager).GetTypeInfo().Assembly; var attributes = assembly.GetCustomAttributes(typeof(DefaultConfigAttribute), false); foreach (DefaultConfigAttribute dca in attributes) { ALog.Debug($"{dca.Key} = {dca.Value}"); if (dca.Key == "PreloadPath") { preloadPath = dca.Value; } } if (!Initialize(preloadPath)) { ALog.Debug($"Failed to Initialized with {preloadPath}"); } } catch(Exception e) { ALog.Debug("Exception at Preparing"); PrintException(e); } } private static void PrintException(Exception exception) { while (exception != null) { ALog.Debug(exception.ToString()); exception = exception.InnerException; } } public static void UnhandledExceptionHandler(object sender, object args) { TypeInfo unhandledExceptionEventArgsType = Type.GetType("UnhandledExceptionEventArgs").GetTypeInfo(); PropertyInfo exception = unhandledExceptionEventArgsType.GetProperty("ExceptionObject"); Exception e = (Exception)exception.GetValue(args); PrintException(e); } public static bool Initialize(string preloadFile) { try { // Set UnhandledException handler with reflection // we must replace this to no reflection method after AppDomain is comming in used net standard TypeInfo appdomainType = Type.GetType("System.AppDomain").GetTypeInfo(); PropertyInfo currentDomain = appdomainType.GetProperty("CurrentDomain", BindingFlags.Public | BindingFlags.Static); EventInfo unhandledException = appdomainType.GetDeclaredEvent("UnhandledException"); object appdomain = currentDomain.GetValue(null, null); MethodInfo handlerInfo = typeof(AssemblyManager).GetTypeInfo().GetDeclaredMethod("UnhandledExceptionHandler"); Delegate handler = handlerInfo.CreateDelegate(unhandledException.EventHandlerType); var addMethod = unhandledException.GetAddMethod(true); addMethod.Invoke(appdomain, new[] {handler}); } catch (Exception e) { ALog.Debug("Exception on set handler for unhandled exception"); PrintException(e); } try { CurrentAssemblyLoaderContext = new AssemblyLoader(); if (!string.IsNullOrEmpty(preloadFile)) { ALog.Debug($"Load from [{preloadFile}]"); FileInfo f = new FileInfo(preloadFile); if (File.Exists(f.FullName)) { using (StreamReader sr = File.OpenText(f.FullName)) { string s = String.Empty; while ((s = sr.ReadLine()) != null) { 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); } // this works strange, vm can't load types except loaded in here. // so user code spit out not found exception. /* if (asm != null) { foreach (TypeInfo t in asm.DefinedTypes) { ALog.Debug("===> TYPE : " + t.FullName); GC.KeepAlive(t.AsType()); } } */ } catch (Exception e) { ALog.Debug("Exception on preload"); PrintException(e); } } } } } } catch (Exception e) { ALog.Debug("Exception on Initialized"); PrintException(e); return false; } return true; } public static void Execute(string dllPath, string[] argv) { try { 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); } 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}); } } catch (Exception e) { ALog.Debug("Exception on Execute"); PrintException(e); } } public static AssemblyLoader CurrentAssemblyLoaderContext { get; private set; } } }