From: hjhun <36876573+hjhun@users.noreply.github.com> Date: Wed, 24 Jan 2024 04:25:35 +0000 (+0900) Subject: [NUI.Gadget] Implement Unload() method (#5897) X-Git-Tag: submit/tizen/20240124.080400~1^2~4 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=722344637d09f23a725e44677e1fcf3439b43ae5;p=platform%2Fcore%2Fcsapi%2Ftizenfx.git [NUI.Gadget] Implement Unload() method (#5897) To unload the loaded assembly, NUIGadgetManager.Unload() method is added. Signed-off-by: Hwankyu Jhun --- diff --git a/src/Tizen.NUI.Gadget/Tizen.NUI/NUIGadgetAssembly.cs b/src/Tizen.NUI.Gadget/Tizen.NUI/NUIGadgetAssembly.cs new file mode 100644 index 000000000..9cfb19969 --- /dev/null +++ b/src/Tizen.NUI.Gadget/Tizen.NUI/NUIGadgetAssembly.cs @@ -0,0 +1,95 @@ +/* +* Copyright (c) 2024 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; + +namespace Tizen.NUI +{ + internal class NUIGadgetAssemblyLoadContext : AssemblyLoadContext + { + public NUIGadgetAssemblyLoadContext() : base(isCollectible: true) + { + } + + protected override Assembly Load(AssemblyName name) + { + return null; + } + } + + internal class NUIGadgetAssembly + { + private static readonly object _assemblyLock = new object(); + private readonly string _assemblyPath; + private WeakReference _assemblyRef; + private Assembly _assembly = null; + + public NUIGadgetAssembly(string assemblyPath) { _assemblyPath = assemblyPath; } + + public void Load() + { + lock (_assemblyLock) + { + if (_assembly != null) + { + return; + } + + Log.Warn("Load(): " + _assemblyPath + " ++"); + NUIGadgetAssemblyLoadContext context = new NUIGadgetAssemblyLoadContext(); + _assemblyRef = new WeakReference(context); + using (MemoryStream memoryStream = new MemoryStream(File.ReadAllBytes(_assemblyPath))) + { + _assembly = context.LoadFromStream(memoryStream); + } + Log.Warn("Load(): " + _assemblyPath + " --"); + } + } + + public bool IsLoaded { get { return _assembly != null; } } + + public NUIGadget CreateInstance(string className) + { + lock (_assemblyLock) + { + return (NUIGadget)_assembly?.CreateInstance(className); + } + } + + public void Unload() + { + lock (_assemblyLock) + { + if (_assembly == null) + { + return; + } + + Log.Warn("Unload(): " + _assemblyPath + " ++"); + if (_assemblyRef.IsAlive) + { + (_assemblyRef.Target as NUIGadgetAssemblyLoadContext).Unload(); + } + + _assembly = null; + Log.Warn("Unload(): " + _assemblyPath + " --"); + } + } + } +} \ No newline at end of file diff --git a/src/Tizen.NUI.Gadget/Tizen.NUI/NUIGadgetInfo.cs b/src/Tizen.NUI.Gadget/Tizen.NUI/NUIGadgetInfo.cs index 6a959cb34..6f177c7ea 100755 --- a/src/Tizen.NUI.Gadget/Tizen.NUI/NUIGadgetInfo.cs +++ b/src/Tizen.NUI.Gadget/Tizen.NUI/NUIGadgetInfo.cs @@ -108,7 +108,7 @@ namespace Tizen.NUI internal string ResourceClassName { get; set; } - internal Assembly Assembly { get; set; } + internal NUIGadgetAssembly Assembly { get; private set; } internal static NUIGadgetInfo CreateNUIGadgetInfo(string packageId) { @@ -199,6 +199,7 @@ namespace Tizen.NUI Log.Warn("Failed to destroy package info. error = " + errorCode); } + info.Assembly = new NUIGadgetAssembly(info.ResourcePath + info.ExecutableFile); return info; } } diff --git a/src/Tizen.NUI.Gadget/Tizen.NUI/NUIGadgetManager.cs b/src/Tizen.NUI.Gadget/Tizen.NUI/NUIGadgetManager.cs index bd3025cf5..9773961e9 100755 --- a/src/Tizen.NUI.Gadget/Tizen.NUI/NUIGadgetManager.cs +++ b/src/Tizen.NUI.Gadget/Tizen.NUI/NUIGadgetManager.cs @@ -21,8 +21,10 @@ using System.IO; using Tizen.Applications; using System.ComponentModel; using System.Runtime.InteropServices; +using System.Runtime.Loader; using System.Reflection; using System.Threading.Tasks; +using System.Security.AccessControl; namespace Tizen.NUI { @@ -144,17 +146,54 @@ namespace Tizen.NUI } NUIGadgetInfo info = Find(resourceType); + Load(info); + } + + private static void Load(NUIGadgetInfo info) + { + if (info == null) + { + throw new ArgumentException("Invalid argument"); + } + try { - Load(info); + lock (info) + { + if (!info.Assembly.IsLoaded) + { + info.Assembly.Load(); + } + } } catch (FileLoadException e) { throw new InvalidOperationException(e.Message); } + catch (BadImageFormatException e) + { + throw new InvalidOperationException(e.Message); + } } - private static void Load(NUIGadgetInfo info) + /// + /// Unloads the loaded assembly of the NUIGadget. + /// + /// The resource type of the NUIGadget package. + /// Thrown when failed because of a invalid argument. + /// 11 + public static void Unload(string resourceType) + { + if (string.IsNullOrEmpty(resourceType)) + { + throw new ArgumentException("Invalid argument"); + } + + NUIGadgetInfo info = Find(resourceType); + Unload(info); + } + + private static void Unload(NUIGadgetInfo info) { if (info == null) { @@ -163,11 +202,9 @@ namespace Tizen.NUI lock (info) { - if (info.Assembly == null) + if (info.Assembly.IsLoaded) { - Log.Warn("NUIGadgetAssembly.Load(): " + info.ResourcePath + info.ExecutableFile + " ++"); - info.Assembly = Assembly.Load(File.ReadAllBytes(info.ResourcePath + info.ExecutableFile)); - Log.Warn("NUIGadgetAssembly.Load(): " + info.ResourcePath + info.ExecutableFile + " --"); + info.Assembly.Unload(); } } } @@ -189,16 +226,9 @@ namespace Tizen.NUI } NUIGadgetInfo info = Find(resourceType); - try - { - Load(info); - } - catch (FileLoadException e) - { - throw new InvalidOperationException(e.Message); - } + Load(info); - NUIGadget gadget = info.Assembly.CreateInstance(className, true) as NUIGadget; + NUIGadget gadget = info.Assembly.CreateInstance(className); if (gadget == null) { throw new InvalidOperationException("Failed to create instance. className: " + className);