• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2024-2025 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 use asset_common::{CallingInfo, Counter, Group, OwnerType, TaskManager, GROUP_SEPARATOR};
17 use asset_db_operator::{
18     database::{get_path, Database},
19     database_file_upgrade::construct_splited_db_name,
20     types::{column, DbMap, QueryOptions},
21 };
22 use asset_file_operator::de_operator::create_user_de_dir;
23 use asset_log::{loge, logi};
24 use asset_sdk::{
25     log_throw_error,
26     plugin_interface::{ExtDbMap, IAssetPlugin, IAssetPluginCtx, RETURN_LIMIT, RETURN_OFFSET},
27     AssetError, ErrCode, Extension, Result, SyncStatus, Value,
28 };
29 use asset_utils::time;
30 use ylong_runtime::task::JoinHandle;
31 use std::{
32     cell::RefCell,
33     sync::{Arc, Mutex},
34 };
35 
36 /// The asset_ext plugin.
37 #[derive(Default)]
38 pub struct AssetPlugin {
39     lib: RefCell<Option<libloading::Library>>,
40 }
41 
42 static ASSET_PLUGIN_LOCK: Mutex<()> = Mutex::new(());
43 
44 unsafe impl Sync for AssetPlugin {}
45 
46 impl AssetPlugin {
new() -> Self47     fn new() -> Self {
48         Self { lib: RefCell::new(None) }
49     }
50 
51     /// Get the instance of AssetPlugin.
get_instance() -> Arc<AssetPlugin>52     pub fn get_instance() -> Arc<AssetPlugin> {
53         static mut INSTANCE: Option<Arc<AssetPlugin>> = None;
54         let _guard = ASSET_PLUGIN_LOCK.lock().unwrap();
55         unsafe { INSTANCE.get_or_insert_with(|| Arc::new(AssetPlugin::new())).clone() }
56     }
57 
58     /// Load the plugin.
load_plugin(&self) -> Result<Box<dyn IAssetPlugin>>59     pub fn load_plugin(&self) -> Result<Box<dyn IAssetPlugin>> {
60         unsafe {
61             let _guard = ASSET_PLUGIN_LOCK.lock().unwrap();
62             if self.lib.borrow().is_none() {
63                 logi!("start to load asset_ext plugin.");
64                 match libloading::Library::new("libasset_ext_ffi.z.so") {
65                     Ok(lib) => *self.lib.borrow_mut() = Some(lib),
66                     Err(err) => {
67                         loge!("dlopen libasset_ext_ffi.z.so failed, err: {}", err);
68                         return log_throw_error!(ErrCode::InvalidArgument, "dlopen failed {}", err);
69                     },
70                 };
71             }
72 
73             let Some(ref lib) = *self.lib.borrow() else {
74                 return log_throw_error!(ErrCode::InvalidArgument, "unexpect error");
75             };
76 
77             let func = match lib
78                 .get::<libloading::Symbol<unsafe extern "C" fn() -> *mut dyn IAssetPlugin>>(b"_create_plugin")
79             {
80                 Ok(func) => func,
81                 Err(err) => {
82                     loge!("dlsym _create_plugin failed, err: {}", err);
83                     return log_throw_error!(ErrCode::InvalidArgument, "dlsym failed {}", err);
84                 },
85             };
86 
87             let plugin_ptr = func();
88             if plugin_ptr.is_null() {
89                 loge!("_create_plugin return null.");
90                 return log_throw_error!(ErrCode::InvalidArgument, "_create_plugin return null.");
91             }
92 
93             Ok(Box::from_raw(plugin_ptr))
94         }
95     }
96 
97     /// Unload plugin.
unload_plugin(&self)98     pub fn unload_plugin(&self) {
99         let _guard = ASSET_PLUGIN_LOCK.lock().unwrap();
100         if self.lib.borrow().is_some() {
101             *self.lib.borrow_mut() = None;
102         }
103     }
104 }
105 
106 /// The asset_ext plugin context.
107 #[repr(C)]
108 pub struct AssetContext {
109     /// The asset database's user id.
110     pub user_id: i32,
111 }
112 
113 
convert_db_map(attributes: &ExtDbMap) -> Result<DbMap>114 fn convert_db_map(attributes: &ExtDbMap) -> Result<DbMap> {
115     let owner_info = attributes.get_bytes_attr(&column::OWNER)?;
116     let owner_type = attributes.get_enum_attr::<OwnerType>(&column::OWNER_TYPE)?;
117     let mut db_map = DbMap::new();
118     db_map.insert_attr(column::OWNER, owner_info.clone());
119     db_map.insert_attr(column::OWNER_TYPE, owner_type);
120     Ok(db_map)
121 }
122 
get_db_name(user_id: i32, attributes: &ExtDbMap, is_ce: bool) -> std::result::Result<String, AssetError>123 fn get_db_name(user_id: i32, attributes: &ExtDbMap, is_ce: bool) -> std::result::Result<String, AssetError> {
124     let owner_info = attributes.get_bytes_attr(&column::OWNER)?;
125     let owner_type = attributes.get_enum_attr::<OwnerType>(&column::OWNER_TYPE)?;
126     let calling_info = match attributes.get(&column::GROUP_ID) {
127         Some(Value::Bytes(group)) => {
128             let mut parts = group.split(|&byte| byte == GROUP_SEPARATOR as u8);
129             let developer_id: Vec<u8> = parts.next().unwrap().to_vec();
130             let group_id: Vec<u8> = parts.next().unwrap().to_vec();
131             CallingInfo::new(user_id, owner_type, owner_info.to_vec(), Some(Group { developer_id, group_id }))
132         },
133         _ => CallingInfo::new(user_id, owner_type, owner_info.to_vec(), None),
134     };
135     construct_splited_db_name(&calling_info, is_ce)
136 }
137 
get_query_options(attrs: &ExtDbMap) -> QueryOptions138 fn get_query_options(attrs: &ExtDbMap) -> QueryOptions {
139     QueryOptions {
140         offset: match attrs.get(RETURN_OFFSET) {
141             Some(Value::Number(offset)) => Some(*offset),
142             _ => None,
143         },
144         limit: match attrs.get(RETURN_LIMIT) {
145             Some(Value::Number(limit)) => Some(*limit),
146             _ => None,
147         },
148         order_by: None,
149         order: None,
150         amend: None,
151     }
152 }
153 
154 #[allow(dead_code)]
155 impl IAssetPluginCtx for AssetContext {
156     /// Initializes the plugin before usage.
init(&mut self, user_id: i32) -> std::result::Result<(), u32>157     fn init(&mut self, user_id: i32) -> std::result::Result<(), u32> {
158         create_user_de_dir(user_id).map_err(|e| e.code as u32)?;
159         self.user_id = user_id;
160         Ok(())
161     }
162 
163     /// Create adapt cloud table for certain asset db.
create_adapt_cloud_table_for_specific_db( &self, db_info: &ExtDbMap, is_ce: bool, ) -> std::result::Result<(), u32>164     fn create_adapt_cloud_table_for_specific_db(
165         &self,
166         db_info: &ExtDbMap,
167         is_ce: bool,
168     ) -> std::result::Result<(), u32> {
169         let db_name = get_db_name(self.user_id, db_info, is_ce).map_err(|e| e.code as u32)?;
170         let mut db = Database::build_with_file_name(self.user_id, &db_name, is_ce).map_err(|e| e.code as u32)?;
171         db.create_adapt_cloud_table().map_err(|e| e.code as u32)
172     }
173 
174     /// Adds an asset to de db.
add(&self, attributes: &ExtDbMap) -> std::result::Result<i32, u32>175     fn add(&self, attributes: &ExtDbMap) -> std::result::Result<i32, u32> {
176         let db_name = get_db_name(self.user_id, attributes, false).map_err(|e| e.code as u32)?;
177         let mut db = Database::build_with_file_name(self.user_id, &db_name, false).map_err(|e| e.code as u32)?;
178         db.insert_datas(attributes).map_err(|e| e.code as u32)
179     }
180 
181     /// Adds an asset to ce db.
ce_add(&self, attributes: &ExtDbMap) -> std::result::Result<i32, u32>182     fn ce_add(&self, attributes: &ExtDbMap) -> std::result::Result<i32, u32> {
183         let db_name = get_db_name(self.user_id, attributes, true).map_err(|e| e.code as u32)?;
184         let mut db = Database::build_with_file_name(self.user_id, &db_name, true).map_err(|e| e.code as u32)?;
185         db.insert_datas(attributes).map_err(|e| e.code as u32)
186     }
187 
188     /// Adds an asset to db in asset and adapt table.
add_cloud_adapt_data( &self, attributes: &ExtDbMap, adapt_attributes: &ExtDbMap, is_ce: bool, need_lock: bool, ) -> std::result::Result<i32, u32>189     fn add_cloud_adapt_data(
190         &self, attributes: &ExtDbMap, adapt_attributes: &ExtDbMap, is_ce: bool, need_lock: bool,
191     ) -> std::result::Result<i32, u32> {
192         let db_name = get_db_name(self.user_id, attributes, is_ce).map_err(|e| e.code as u32)?;
193         if need_lock {
194             let mut db = Database::build_with_file_name(self.user_id, &db_name, is_ce).map_err(|e| e.code as u32)?;
195             db.insert_cloud_adapt_data(attributes, adapt_attributes).map_err(|e| e.code as u32)
196         } else {
197             let mut db = Database::build_with_file_name_without_lock(self.user_id, &db_name, is_ce).map_err(|e| e.code as u32)?;
198             db.insert_cloud_adapt_data_without_lock(attributes, adapt_attributes).map_err(|e| e.code as u32)
199         }
200     }
201 
202     /// Adds an asset with replace to de db.
replace(&self, condition: &ExtDbMap, attributes: &ExtDbMap) -> std::result::Result<(), u32>203     fn replace(&self, condition: &ExtDbMap, attributes: &ExtDbMap) -> std::result::Result<(), u32> {
204         let db_name = get_db_name(self.user_id, attributes, false).map_err(|e| e.code as u32)?;
205         let mut db = Database::build_with_file_name(self.user_id, &db_name, false).map_err(|e| e.code as u32)?;
206         db.replace_datas(condition, false, attributes).map_err(|e| e.code as u32)
207     }
208 
209     /// Adds an asset with replace to ce db.
ce_replace(&self, condition: &ExtDbMap, attributes: &ExtDbMap) -> std::result::Result<(), u32>210     fn ce_replace(&self, condition: &ExtDbMap, attributes: &ExtDbMap) -> std::result::Result<(), u32> {
211         let db_name = get_db_name(self.user_id, attributes, true).map_err(|e| e.code as u32)?;
212         let mut db = Database::build_with_file_name(self.user_id, &db_name, true).map_err(|e| e.code as u32)?;
213         db.replace_datas(condition, false, attributes).map_err(|e| e.code as u32)
214     }
215 
216     /// Queries de db.
query(&self, attributes: &ExtDbMap) -> std::result::Result<Vec<ExtDbMap>, u32>217     fn query(&self, attributes: &ExtDbMap) -> std::result::Result<Vec<ExtDbMap>, u32> {
218         let de_dbs = asset_file_operator::de_operator::get_de_user_dbs(self.user_id).map_err(|e| e.code as u32)?;
219         let mut query_data = vec![];
220         for db_name in de_dbs {
221             let mut db = Database::build_with_file_name(self.user_id, &db_name, false).map_err(|e| e.code as u32)?;
222             query_data.extend(db.query_datas(&vec![], attributes, None, false).map_err(|e| e.code as u32)?);
223         }
224         Ok(query_data)
225     }
226 
227     /// Queries ce db.
ce_query(&self, attributes: &ExtDbMap) -> std::result::Result<Vec<ExtDbMap>, u32>228     fn ce_query(&self, attributes: &ExtDbMap) -> std::result::Result<Vec<ExtDbMap>, u32> {
229         let ce_dbs = asset_file_operator::ce_operator::get_ce_user_dbs(self.user_id).map_err(|e| e.code as u32)?;
230         let mut query_data = vec![];
231         for db_name in ce_dbs {
232             let mut db = Database::build_with_file_name(self.user_id, &db_name, true).map_err(|e| e.code as u32)?;
233             query_data.extend(db.query_datas(&vec![], attributes, None, false).map_err(|e| e.code as u32)?);
234         }
235         Ok(query_data)
236     }
237 
query_target_data( &self, db_name: &str, columns: &[&'static str], sql_where: &str, limit: u32, offset: u32, is_ce: bool, ) -> std::result::Result<Vec<ExtDbMap>, u32>238     fn query_target_data(
239         &self,
240         db_name: &str,
241         columns: &[&'static str],
242         sql_where: &str,
243         limit: u32,
244         offset: u32,
245         is_ce: bool,
246     ) -> std::result::Result<Vec<ExtDbMap>, u32> {
247         let mut db = Database::build_with_file_name(self.user_id, db_name, is_ce).map_err(|e| e.code as u32)?;
248         let condition = ExtDbMap::new();
249         let query_options = QueryOptions {
250             offset: Some(offset),
251             limit: Some(limit),
252             order: None,
253             order_by: None,
254             amend: Some(sql_where.to_string()),
255         };
256         let query_data =
257             db.query_datas(&columns.to_vec(), &condition, Some(&query_options), false).map_err(|e| e.code as u32)?;
258         Ok(query_data)
259     }
260 
261     /// Query db with attributes to a certain db. Normal, Group, CE.
query_certain_db( &self, db_info: &ExtDbMap, attributes: &ExtDbMap, query_options: &ExtDbMap, is_ce: bool, is_filter_sync: bool, ) -> std::result::Result<Vec<ExtDbMap>, u32>262     fn query_certain_db(
263         &self,
264         db_info: &ExtDbMap,
265         attributes: &ExtDbMap,
266         query_options: &ExtDbMap,
267         is_ce: bool,
268         is_filter_sync: bool,
269     ) -> std::result::Result<Vec<ExtDbMap>, u32> {
270         let db_name = get_db_name(self.user_id, db_info, is_ce).map_err(|e| e.code as u32)?;
271         let mut db = Database::build_with_file_name(self.user_id, &db_name, is_ce).map_err(|e| e.code as u32)?;
272         db.query_datas(&vec![], attributes, Some(&get_query_options(query_options)), is_filter_sync).map_err(|e| e.code as u32)
273     }
274 
275     /// Query db with attributes to a certain db. Normal, Group, CE.
query_certain_db_with_connect_table( &self, db_info: &ExtDbMap, attributes: &ExtDbMap, is_ce: bool, need_lock: bool, ) -> std::result::Result<Vec<ExtDbMap>, u32>276     fn query_certain_db_with_connect_table(
277         &self,
278         db_info: &ExtDbMap,
279         attributes: &ExtDbMap,
280         is_ce: bool,
281         need_lock: bool,
282     ) -> std::result::Result<Vec<ExtDbMap>, u32> {
283         let db_name = get_db_name(self.user_id, db_info, is_ce).map_err(|e| e.code as u32)?;
284 
285         if need_lock {
286             let mut db = Database::build_with_file_name(self.user_id, &db_name, is_ce).map_err(|e| e.code as u32)?;
287             db.query_datas_with_connect_table(&vec![], attributes, None, false).map_err(|e| e.code as u32)
288         } else {
289             let mut db = Database::build_with_file_name_without_lock(self.user_id, &db_name, is_ce).map_err(|e| e.code as u32)?;
290             db.query_datas_with_connect_table_without_lock(&vec![], attributes, None, false).map_err(|e| e.code as u32)
291         }
292     }
293 
294     /// Removes an asset from de db.
remove(&self, attributes: &ExtDbMap) -> std::result::Result<i32, u32>295     fn remove(&self, attributes: &ExtDbMap) -> std::result::Result<i32, u32> {
296         let de_dbs = asset_file_operator::de_operator::get_de_user_dbs(self.user_id).map_err(|e| e.code as u32)?;
297         let mut total_remove_count = 0;
298         for db_name in de_dbs {
299             let mut db = Database::build_with_file_name(self.user_id, &db_name, false).map_err(|e| e.code as u32)?;
300             total_remove_count += db.delete_datas(attributes, None, false).map_err(|e| e.code as u32)?;
301         }
302         Ok(total_remove_count)
303     }
304 
305     /// Removes an asset from ce db.
ce_remove(&self, attributes: &ExtDbMap) -> std::result::Result<i32, u32>306     fn ce_remove(&self, attributes: &ExtDbMap) -> std::result::Result<i32, u32> {
307         let ce_dbs = asset_file_operator::ce_operator::get_ce_user_dbs(self.user_id).map_err(|e| e.code as u32)?;
308         let mut total_remove_count = 0;
309         for db_name in ce_dbs {
310             let mut db = Database::build_with_file_name(self.user_id, &db_name, true).map_err(|e| e.code as u32)?;
311             total_remove_count += db.delete_datas(attributes, None, false).map_err(|e| e.code as u32)?;
312         }
313         Ok(total_remove_count)
314     }
315 
316     /// Removes assets with aliases.
batch_remove(&self, attributes: &ExtDbMap, aliases: &[Vec<u8>], require_attr_encrypted: bool) -> Result<()>317     fn batch_remove(&self, attributes: &ExtDbMap, aliases: &[Vec<u8>], require_attr_encrypted: bool) -> Result<()> {
318         let db_name = get_db_name(self.user_id, attributes, require_attr_encrypted)?;
319         let mut db = Database::build_with_file_name(self.user_id, &db_name, require_attr_encrypted)?;
320         let condition = convert_db_map(attributes)?;
321         let mut update_datas = DbMap::new();
322         let time = time::system_time_in_millis()?;
323         update_datas.insert(column::UPDATE_TIME, Value::Bytes(time));
324         update_datas.insert(column::SYNC_STATUS, Value::Number(SyncStatus::SyncDel as u32));
325         let total_removed_count = db.delete_batch_datas(&condition, &update_datas, aliases)?;
326         logi!("total removed count = {}", total_removed_count);
327         Ok(())
328     }
329 
330     /// Removes an asset from a certain db. Normal, Group, CE.
remove_certain_db( &self, db_info: &ExtDbMap, attributes: &ExtDbMap, is_ce: bool, ) -> std::result::Result<i32, u32>331     fn remove_certain_db(
332         &self,
333         db_info: &ExtDbMap,
334         attributes: &ExtDbMap,
335         is_ce: bool,
336     ) -> std::result::Result<i32, u32> {
337         let db_name = get_db_name(self.user_id, db_info, is_ce).map_err(|e| e.code as u32)?;
338         let mut db = Database::build_with_file_name(self.user_id, &db_name, is_ce).map_err(|e| e.code as u32)?;
339         db.delete_datas(attributes, None, false).map_err(|e| e.code as u32)
340     }
341 
342     /// Removes assets from de db with sepcific condition.
remove_with_specific_cond( &self, specific_cond: &str, condition_value: &[Value], ) -> std::result::Result<i32, u32>343     fn remove_with_specific_cond(
344         &self,
345         specific_cond: &str,
346         condition_value: &[Value],
347     ) -> std::result::Result<i32, u32> {
348         let de_dbs = asset_file_operator::de_operator::get_de_user_dbs(self.user_id).map_err(|e| e.code as u32)?;
349         let mut total_remove_count = 0;
350         for db_name in de_dbs {
351             let mut db = Database::build_with_file_name(self.user_id, &db_name, false).map_err(|e| e.code as u32)?;
352             total_remove_count +=
353                 db.delete_specific_condition_datas(specific_cond, condition_value).map_err(|e| e.code as u32)?;
354         }
355         Ok(total_remove_count)
356     }
357 
358     /// Removes assets from ce db with sepcific condition.
ce_remove_with_specific_cond( &self, specific_cond: &str, condition_value: &[Value], ) -> std::result::Result<i32, u32>359     fn ce_remove_with_specific_cond(
360         &self,
361         specific_cond: &str,
362         condition_value: &[Value],
363     ) -> std::result::Result<i32, u32> {
364         let ce_dbs = asset_file_operator::ce_operator::get_ce_user_dbs(self.user_id).map_err(|e| e.code as u32)?;
365         let mut total_remove_count = 0;
366         for db_name in ce_dbs {
367             let mut db = Database::build_with_file_name(self.user_id, &db_name, true).map_err(|e| e.code as u32)?;
368             total_remove_count +=
369                 db.delete_specific_condition_datas(specific_cond, condition_value).map_err(|e| e.code as u32)?;
370         }
371         Ok(total_remove_count)
372     }
373 
374     /// Remove an asset to db in asset and adapt table.
remove_cloud_adapt_data( &self, db_info: &ExtDbMap, attributes: Option<&ExtDbMap>, adapt_attributes: Option<&ExtDbMap>, is_ce: bool, need_lock: bool, ) -> std::result::Result<i32, u32>375     fn remove_cloud_adapt_data(
376         &self,
377         db_info: &ExtDbMap,
378         attributes: Option<&ExtDbMap>,
379         adapt_attributes: Option<&ExtDbMap>,
380         is_ce: bool,
381         need_lock: bool,
382     ) -> std::result::Result<i32, u32> {
383         let db_name = get_db_name(self.user_id, db_info, is_ce).map_err(|e| e.code as u32)?;
384         if need_lock {
385             let mut db = Database::build_with_file_name(self.user_id, &db_name, is_ce).map_err(|e| e.code as u32)?;
386             db.delete_adapt_data(attributes, adapt_attributes).map_err(|e| e.code as u32)
387         } else {
388             let mut db = Database::build_with_file_name_without_lock(self.user_id, &db_name, is_ce).map_err(|e| e.code as u32)?;
389             db.delete_adapt_data_without_lock(attributes, adapt_attributes).map_err(|e| e.code as u32)
390         }
391     }
392 
393     /// Updates the attributes of an asset in de db.
update(&self, attributes: &ExtDbMap, attrs_to_update: &ExtDbMap) -> std::result::Result<i32, u32>394     fn update(&self, attributes: &ExtDbMap, attrs_to_update: &ExtDbMap) -> std::result::Result<i32, u32> {
395         let de_dbs = asset_file_operator::de_operator::get_de_user_dbs(self.user_id).map_err(|e| e.code as u32)?;
396         let mut total_update_count = 0;
397         for db_name in de_dbs {
398             let mut db = Database::build_with_file_name(self.user_id, &db_name, false).map_err(|e| e.code as u32)?;
399             total_update_count += db.update_datas(attributes, false, attrs_to_update).map_err(|e| e.code as u32)?;
400         }
401         Ok(total_update_count)
402     }
403 
404     /// Updates the attributes of an asset in ce db.
ce_update(&self, attributes: &ExtDbMap, attrs_to_update: &ExtDbMap) -> std::result::Result<i32, u32>405     fn ce_update(&self, attributes: &ExtDbMap, attrs_to_update: &ExtDbMap) -> std::result::Result<i32, u32> {
406         let ce_dbs = asset_file_operator::ce_operator::get_ce_user_dbs(self.user_id).map_err(|e| e.code as u32)?;
407         let mut total_update_count = 0;
408         for db_name in ce_dbs {
409             let mut db = Database::build_with_file_name(self.user_id, &db_name, true).map_err(|e| e.code as u32)?;
410             total_update_count += db.update_datas(attributes, false, attrs_to_update).map_err(|e| e.code as u32)?;
411         }
412         Ok(total_update_count)
413     }
414 
get_certain_db_lock( &self, db_info: &ExtDbMap, is_ce: bool, ) -> std::result::Result<Arc<Mutex<i32>>, u32>415     fn get_certain_db_lock(
416         &self,
417         db_info: &ExtDbMap,
418         is_ce: bool,
419     ) -> std::result::Result<Arc<Mutex<i32>>, u32> {
420         let db_name = get_db_name(self.user_id, db_info, is_ce).map_err(|e| e.code as u32)?;
421         let db = Database::build_with_file_name(self.user_id, &db_name, is_ce).map_err(|e| e.code as u32)?;
422         let lock = db.get_db_lock().map_err(|e| e.code as u32)?;
423         Ok(lock)
424     }
425 
426     /// Returns the storage path for de db.
get_storage_path(&self) -> String427     fn get_storage_path(&self) -> String {
428         get_path()
429     }
430 
431     /// Increase count
increase_count(&self)432     fn increase_count(&self) {
433         let counter = Counter::get_instance();
434         counter.lock().unwrap().increase_count();
435     }
436 
437     /// Decrease count
decrease_count(&self)438     fn decrease_count(&self) {
439         let counter = Counter::get_instance();
440         counter.lock().unwrap().decrease_count();
441     }
442 
443     /// Add task
add_task(&self, handle: JoinHandle<()>)444     fn add_task(&self, handle: JoinHandle<()>) {
445         let task_manager = TaskManager::get_instance();
446         task_manager.lock().unwrap().push_task(handle);
447     }
448 }
449