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