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