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