Fix unused native image in application.
[platform/core/dotnet/launcher.git] / Tizen.Runtime / Tizen.Runtime.Coreclr / AssemblyManager.cs
1 /*
2  * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  * Licensed under the Apache License, Version 2.0 (the License);
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an AS IS BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 using System;
18 using System.IO;
19 using System.Reflection;
20 using System.Runtime.Loader;
21 using System.Linq;
22 using System.Runtime.InteropServices;
23
24 namespace Tizen.Runtime.Coreclr
25 {
26     public static class AssemblyManager
27     {
28         public static bool Launch(
29                 [In] string rootPath,
30                 [In] string path,
31                 [In] int argc,
32                 [MarshalAs(UnmanagedType.LPArray, SizeParamIndex=2)]
33                 [In] string[] argv)
34         {
35             ALog.Debug($"Application Launch path : {path}");
36             try
37             {
38                 DirectoryInfo bindir = new DirectoryInfo(Path.Combine(rootPath, "bin"));
39                 DirectoryInfo libdir = new DirectoryInfo(Path.Combine(rootPath, "lib"));
40                 if (Directory.Exists(bindir.FullName))
41                 {
42                     CurrentAssemblyLoaderContext.AddSearchableDirectory(bindir.FullName);
43                 }
44                 if (Directory.Exists(libdir.FullName))
45                 {
46                     CurrentAssemblyLoaderContext.AddSearchableDirectory(libdir.FullName);
47                 }
48                 Execute(path, argv);
49             }
50             catch(Exception e)
51             {
52                 ALog.Debug("Exception in Launch()");
53                 PrintException(e);
54                 return false;
55             }
56
57             return true;
58         }
59
60         public static void Prepared()
61         {
62             try
63             {
64                 string preloadPath = "";
65                 ICustomAttributeProvider assembly = typeof(AssemblyManager).GetTypeInfo().Assembly;
66                 var attributes = assembly.GetCustomAttributes(typeof(DefaultConfigAttribute), false);
67                 foreach (DefaultConfigAttribute dca in attributes)
68                 {
69                     ALog.Debug($"{dca.Key} = {dca.Value}");
70                     if (dca.Key == "PreloadPath")
71                     {
72                         preloadPath = dca.Value;
73                     }
74                 }
75
76                 if (!Initialize(preloadPath))
77                 {
78                     ALog.Debug($"Failed to Initialized with {preloadPath}");
79                 }
80             }
81             catch(Exception e)
82             {
83                 ALog.Debug("Exception at Preparing");
84                 PrintException(e);
85             }
86         }
87
88         private static void PrintException(Exception exception)
89         {
90             while (exception != null)
91             {
92                 ALog.Debug(exception.ToString());
93                 exception = exception.InnerException;
94             }
95         }
96
97         public static void UnhandledExceptionHandler(object sender, object args)
98         {
99             TypeInfo unhandledExceptionEventArgsType =
100                 Type.GetType("UnhandledExceptionEventArgs").GetTypeInfo();
101
102             PropertyInfo exception = unhandledExceptionEventArgsType.GetProperty("ExceptionObject");
103             Exception e = (Exception)exception.GetValue(args);
104
105             PrintException(e);
106         }
107
108         public static bool Initialize(string preloadDirectory)
109         {
110             try
111             {
112                 // Set UnhandledException handler with reflection
113                 // we must replace this to no reflection method after AppDomain is comming in used net standard
114                 TypeInfo appdomainType = Type.GetType("System.AppDomain").GetTypeInfo();
115                 PropertyInfo currentDomain = appdomainType.GetProperty("CurrentDomain",
116                         BindingFlags.Public | BindingFlags.Static);
117                 EventInfo unhandledException = appdomainType.GetDeclaredEvent("UnhandledException");
118                 object appdomain = currentDomain.GetValue(null, null);
119                 MethodInfo handlerInfo = typeof(AssemblyManager).GetTypeInfo().GetDeclaredMethod("UnhandledExceptionHandler");
120                 Delegate handler = handlerInfo.CreateDelegate(unhandledException.EventHandlerType);
121                 var addMethod = unhandledException.GetAddMethod(true);
122                 addMethod.Invoke(appdomain, new[] {handler});
123
124             }
125             catch (Exception e)
126             {
127                 ALog.Debug("Exception on set handler for unhandled exception");
128                 PrintException(e);
129             }
130
131             try
132             {
133                 CurrentAssemblyLoaderContext = new AssemblyLoader();
134
135                 if (!string.IsNullOrEmpty(preloadDirectory))
136                 {
137                     ALog.Debug($"Load from [{preloadDirectory}]");
138                     DirectoryInfo d = new DirectoryInfo(preloadDirectory);
139                     if (Directory.Exists(d.FullName))
140                     {
141                         CurrentAssemblyLoaderContext.AddSearchableDirectory(d.FullName);
142                         string[] dlls = Directory.GetFiles(d.FullName, "*.dll");
143
144                         foreach (string dll in dlls)
145                         {
146                             ALog.Debug($"preload dll : {dll}");
147                             CurrentAssemblyLoaderContext.LoadFromAssemblyPath(dll);
148                         }
149                     }
150                 }
151             }
152             catch (Exception e)
153             {
154                 ALog.Debug("Exception on Initialized");
155                 PrintException(e);
156                 return false;
157             }
158             return true;
159         }
160
161         public static void Execute(string dllPath, string[] argv)
162         {
163             try
164             {
165                 FileInfo f = new FileInfo(dllPath);
166                 if (File.Exists(f.FullName))
167                 {
168                     Assembly asm = null;
169                     if (0 == string.Compare(f.FullName, f.FullName.Length - 7, ".ni", 0, 3, StringComparison.OrdinalIgnoreCase))
170                     {
171                         asm = CurrentAssemblyLoaderContext.LoadFromNativeImagePath(f.FullName, null);
172                     }
173                     else
174                     {
175                         asm = CurrentAssemblyLoaderContext.LoadFromAssemblyPath(f.FullName);
176                     }
177
178                     if (asm == null) throw new FileNotFoundException($"{f.FullName} is not found");
179                     if (asm.EntryPoint == null) throw new ArgumentException($"{f.FullName} did not have EntryPoint");
180                     asm.EntryPoint.Invoke(null, new object[]{argv});
181                 }
182             }
183             catch (Exception e)
184             {
185                 ALog.Debug("Exception on Execute");
186                 PrintException(e);
187             }
188         }
189
190         public static AssemblyLoader CurrentAssemblyLoaderContext
191         {
192             get;
193             private set;
194         }
195
196     }
197 }