1 /* 2 * Copyright (C) 2023 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16 //! Plugin manager, On-demand load and unload dynamic library. 17 //! Plugin module supply one group of interfaces, bussiness implement these interfaces 18 //! as a plugin, this plugin can manage by plugin manager. 19 //! Currently there are two plugins, one is mouse and key coordination, another is drag 20 //! interacton. They develop base on plugin manager. 21 22 #![allow(unused_variables)] 23 #![allow(dead_code)] 24 25 use std::collections::HashMap; 26 use std::path::Path; 27 use std::ffi::{ c_char, CString }; 28 29 use hilog_rust::{ debug, info, error, hilog, HiLogLabel, LogType }; 30 31 use fusion_data_rust::{ Intention, IPlugin }; 32 use fusion_utils_rust::call_debug_enter; 33 use fusion_basic_server_rust::FusionBasicServer; 34 35 const LOG_LABEL: HiLogLabel = HiLogLabel { 36 log_type: LogType::LogCore, 37 domain: 0xD002220, 38 tag: "FusionPluginManager" 39 }; 40 41 /// Helper to define intefaces of library that will be used by [`PluginManager`] 42 /// to interact with it. 43 #[macro_export] 44 macro_rules! export_plugin { 45 ($plugin_type:ty) => { 46 /// Create a new instance of [`IPlugin`] through which functionalities 47 /// of this module can be accessed. 48 /// # Safety 49 #[no_mangle] 50 pub unsafe extern "C" fn _create_plugin() -> *mut dyn IPlugin { 51 let boxed = Box::new(<$plugin_type>::default()); 52 Box::into_raw(boxed) 53 } 54 }; 55 } 56 57 /// Loading、unloading and bookkeeping of modules. 58 #[derive(Default)] 59 pub struct PluginManager { 60 loaders: HashMap<Intention, libloading::Library> 61 } 62 63 impl PluginManager { instantiate_loader(&mut self, intention: &Intention)64 fn instantiate_loader(&mut self, intention: &Intention) { 65 call_debug_enter!("PluginManager::instantiate_loader"); 66 let file_path = match intention { 67 Intention::Drag => { 68 Path::new("/system/lib/libfusion_drag_server_ffi.z.so") 69 } 70 Intention::Coordination => { 71 Path::new("/system/lib/libfusion_coordination_server_ffi.z.so") 72 } 73 _ => { 74 return; 75 } 76 }; 77 78 let lib_result = unsafe { 79 libloading::Library::new(file_path.as_os_str()) 80 }; 81 match lib_result { 82 Ok(lib) => { 83 info!(LOG_LABEL, "New Library instance created"); 84 self.loaders.insert(intention.clone(), lib); 85 } 86 Err(_) => { 87 info!(LOG_LABEL, "Failed to create Library instance"); 88 } 89 } 90 } 91 do_load_plugin(&mut self, intention: Intention) -> Option<Box<dyn IPlugin>>92 fn do_load_plugin(&mut self, intention: Intention) -> Option<Box<dyn IPlugin>> { 93 call_debug_enter!("PluginManager::do_load_plugin"); 94 if !self.loaders.contains_key(&intention) { 95 self.instantiate_loader(&intention); 96 } 97 match self.loaders.get(&intention) { 98 Some(loader) => { 99 if let Ok(creator) = unsafe { 100 loader.get::<libloading::Symbol<unsafe extern "C" fn() -> *mut dyn IPlugin>>(b"_create_plugin") 101 } { 102 info!(LOG_LABEL, "Create plugin instance"); 103 let plugin_ptr = unsafe { 104 creator() 105 }; 106 if plugin_ptr.is_null() { 107 error!(LOG_LABEL, "Failed to create plugin instance"); 108 None 109 } else { 110 Some(unsafe { 111 info!(LOG_LABEL, "Plugin is loaded"); 112 Box::from_raw(plugin_ptr) 113 }) 114 } 115 } else { 116 error!(LOG_LABEL, "Symbol is not found"); 117 None 118 } 119 } 120 None => { 121 error!(LOG_LABEL, "Can not instantiate loader"); 122 None 123 } 124 } 125 } 126 127 /// Load module identified by [`intention`]. load_plugin(&mut self, intention: Intention) -> Option<Box<dyn IPlugin>>128 pub fn load_plugin(&mut self, intention: Intention) -> Option<Box<dyn IPlugin>> 129 { 130 call_debug_enter!("PluginManager::load_plugin"); 131 match intention { 132 Intention::Basic => { 133 Some(Box::<FusionBasicServer>::default()) 134 } 135 _ => { 136 self.do_load_plugin(intention) 137 } 138 } 139 } 140 141 /// Unload module identified by [`intention`]. unload_plugin(&mut self, intention: Intention)142 pub fn unload_plugin(&mut self, intention: Intention) { 143 call_debug_enter!("PluginManager::unload_plugin"); 144 if let Some(loader) = self.loaders.remove(&intention) { 145 info!(LOG_LABEL, "Library({}) is unloaded", @public(intention as u32)); 146 } else { 147 debug!(LOG_LABEL, "Library({}) has not been loaded", @public(intention as u32)); 148 } 149 } 150 } 151