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 //! This module is used to subscribe common event and system ability.
17 
18 use std::{
19     ffi::CStr,
20     fs::{self, DirEntry},
21     slice,
22     sync::Mutex,
23     time::{Duration, Instant},
24 };
25 
26 use lazy_static::lazy_static;
27 
28 use asset_common::{AutoCounter, CallingInfo, OwnerType};
29 use asset_crypto_manager::{crypto_manager::CryptoManager, secret_key::SecretKey};
30 use asset_db_key_operator::DbKey;
31 use asset_db_operator::{
32     database::Database,
33     database_file_upgrade::{construct_splited_db_name, trigger_db_upgrade},
34     types::{column, DbMap},
35 };
36 use asset_definition::{log_throw_error, ErrCode, Result, SyncType, Value};
37 use asset_file_operator::{
38     ce_operator::is_db_key_cipher_file_exist,
39     common::{BACKUP_SUFFIX, CE_ROOT_PATH, DB_SUFFIX, DE_ROOT_PATH},
40     de_operator::delete_user_de_dir,
41 };
42 use asset_log::{loge, logi, logw};
43 use asset_plugin::asset_plugin::AssetPlugin;
44 use asset_sdk::plugin_interface::{
45     EventType, ExtDbMap, PARAM_NAME_APP_INDEX, PARAM_NAME_BUNDLE_NAME, PARAM_NAME_IS_HAP, PARAM_NAME_USER_ID,
46 };
47 
48 use crate::sys_event::upload_fault_system_event;
49 
50 /// success code.
51 const SUCCESS: i32 = 0;
52 const USER_ID_VEC_BUFFER: u32 = 5;
53 const MINIMUM_MAIN_USER_ID: i32 = 100;
54 
remove_db(file_path: &str, calling_info: &CallingInfo, is_ce: bool) -> Result<()>55 fn remove_db(file_path: &str, calling_info: &CallingInfo, is_ce: bool) -> Result<()> {
56     let db_name = construct_splited_db_name(calling_info.owner_type_enum(), calling_info.owner_info(), is_ce)?;
57     for db_path in fs::read_dir(file_path)? {
58         let db_path = db_path?;
59         let db_file_name = db_path.file_name().to_string_lossy().to_string();
60         let origin_db_name = format!("{}{}", db_name, DB_SUFFIX);
61         let backup_db_name = format!("{}{}", origin_db_name, BACKUP_SUFFIX);
62         if db_file_name == origin_db_name || db_file_name == backup_db_name {
63             match fs::remove_file(&db_path.path().to_string_lossy().to_string()) {
64                 Ok(_) => (),
65                 Err(e) => {
66                     logw!("[WARNING]Remove db:[{}] failed, error code:[{}]", db_file_name, e);
67                 },
68             }
69         }
70     }
71     Ok(())
72 }
73 
delete_in_de_db_on_package_removed( calling_info: &CallingInfo, delete_cond: &DbMap, reverse_condition: &DbMap, check_cond: &DbMap, ) -> Result<bool>74 fn delete_in_de_db_on_package_removed(
75     calling_info: &CallingInfo,
76     delete_cond: &DbMap,
77     reverse_condition: &DbMap,
78     check_cond: &DbMap,
79 ) -> Result<bool> {
80     // Delete non-persistent data in de db.
81     let mut de_db =
82         Database::build(calling_info.user_id(), calling_info.owner_type_enum(), calling_info.owner_info(), false)?;
83     let _ = de_db.delete_datas(delete_cond, Some(reverse_condition), false)?;
84     let de_db_data_exists = de_db.is_data_exists(check_cond, false)?;
85     // remove db and backup db
86     if !de_db_data_exists {
87         remove_db(&format!("{}/{}", DE_ROOT_PATH, calling_info.user_id()), calling_info, false)?;
88     }
89     Ok(de_db_data_exists)
90 }
91 
delete_in_ce_db_on_package_removed( calling_info: &CallingInfo, delete_cond: &DbMap, reverse_condition: &DbMap, check_cond: &DbMap, ) -> Result<bool>92 fn delete_in_ce_db_on_package_removed(
93     calling_info: &CallingInfo,
94     delete_cond: &DbMap,
95     reverse_condition: &DbMap,
96     check_cond: &DbMap,
97 ) -> Result<bool> {
98     // Delete non-persistent data in ce db if ce db file exists.
99     let mut ce_db =
100         Database::build(calling_info.user_id(), calling_info.owner_type_enum(), calling_info.owner_info(), true)?;
101     let _ = ce_db.delete_datas(delete_cond, Some(reverse_condition), false)?;
102     // Check whether there is still persistent data left in ce db.
103     let ce_db_data_exists = ce_db.is_data_exists(check_cond, false)?;
104     if !ce_db_data_exists {
105         remove_db(&format!("{}/{}/asset_service", CE_ROOT_PATH, calling_info.user_id()), calling_info, false)?;
106     }
107     Ok(ce_db_data_exists)
108 }
109 
delete_on_package_removed(owner: Vec<u8>, calling_info: &CallingInfo) -> Result<bool>110 fn delete_on_package_removed(owner: Vec<u8>, calling_info: &CallingInfo) -> Result<bool> {
111     let mut delete_cond = DbMap::new();
112     delete_cond.insert(column::OWNER_TYPE, Value::Number(OwnerType::Hap as u32));
113     delete_cond.insert(column::OWNER, Value::Bytes(owner.clone()));
114     delete_cond.insert(column::IS_PERSISTENT, Value::Bool(false));
115     let mut reverse_condition = DbMap::new();
116     reverse_condition.insert(column::SYNC_TYPE, Value::Number(SyncType::TrustedAccount as u32));
117     let check_cond = DbMap::new();
118     let de_db_data_exists =
119         delete_in_de_db_on_package_removed(calling_info, &delete_cond, &reverse_condition, &check_cond)?;
120 
121     if is_db_key_cipher_file_exist(calling_info.user_id())? {
122         let ce_db_data_exists =
123             delete_in_ce_db_on_package_removed(calling_info, &delete_cond, &reverse_condition, &check_cond)?;
124         Ok(de_db_data_exists || ce_db_data_exists)
125     } else {
126         Ok(de_db_data_exists)
127     }
128 }
129 
clear_cryptos(calling_info: &CallingInfo)130 fn clear_cryptos(calling_info: &CallingInfo) {
131     let crypto_manager = CryptoManager::get_instance();
132     crypto_manager.lock().unwrap().remove_by_calling_info(calling_info);
133 }
134 
delete_data_by_owner(user_id: i32, owner: *const u8, owner_size: u32)135 fn delete_data_by_owner(user_id: i32, owner: *const u8, owner_size: u32) {
136     let _counter_user = AutoCounter::new();
137     let start_time = Instant::now();
138     let owner: Vec<u8> = unsafe { slice::from_raw_parts(owner, owner_size as usize).to_vec() };
139     let calling_info = CallingInfo::new(user_id, OwnerType::Hap, owner.clone());
140     clear_cryptos(&calling_info);
141     let res = match delete_on_package_removed(owner, &calling_info) {
142         Ok(true) => {
143             logi!("The owner wants to retain data after uninstallation. Do not delete key in HUKS!");
144             Ok(())
145         },
146         Ok(false) => SecretKey::delete_by_owner(&calling_info),
147         Err(e) => {
148             // Report the database operation fault event.
149             upload_fault_system_event(&calling_info, start_time, "on_package_removed", &e);
150             Ok(())
151         },
152     };
153     if let Err(e) = res {
154         // Report the key operation fault event.
155         let calling_info = CallingInfo::new_self();
156         upload_fault_system_event(&calling_info, start_time, "on_package_removed", &e);
157     }
158 }
159 
on_package_removed( user_id: i32, owner: *const u8, owner_size: u32, bundle_name: *const u8, app_index: i32, )160 pub(crate) extern "C" fn on_package_removed(
161     user_id: i32,
162     owner: *const u8,
163     owner_size: u32,
164     bundle_name: *const u8,
165     app_index: i32,
166 ) {
167     delete_data_by_owner(user_id, owner, owner_size);
168 
169     let c_str = unsafe { CStr::from_ptr(bundle_name as _) };
170     let bundle_name = match c_str.to_str() {
171         Ok(s) => s.to_string(),
172         Err(e) => {
173             loge!("[FATAL]Parse sting from bundle name failed, error is {}.", e);
174             return;
175         },
176     };
177 
178     logi!("[INFO]On app -{}-{}-{}- removed.", user_id, bundle_name, app_index);
179 
180     if let Ok(load) = AssetPlugin::get_instance().load_plugin() {
181         let mut params = ExtDbMap::new();
182         params.insert(PARAM_NAME_USER_ID, Value::Number(user_id as u32));
183         params.insert(PARAM_NAME_BUNDLE_NAME, Value::Bytes(bundle_name.as_bytes().to_vec()));
184 
185         // only hap package can be removed
186         params.insert(PARAM_NAME_IS_HAP, Value::Bool(true));
187         params.insert(PARAM_NAME_APP_INDEX, Value::Number(app_index as u32));
188         match load.process_event(EventType::OnPackageClear, &params) {
189             Ok(()) => logi!("process package remove event success."),
190             Err(code) => loge!("process package remove event failed, code: {}", code),
191         }
192     }
193 }
194 
on_user_removed(user_id: i32)195 extern "C" fn on_user_removed(user_id: i32) {
196     let _counter_user = AutoCounter::new();
197     let _ = delete_user_de_dir(user_id);
198     notify_on_user_removed(user_id);
199 }
200 
delete_crypto_need_unlock()201 extern "C" fn delete_crypto_need_unlock() {
202     let _counter_user = AutoCounter::new();
203     let crypto_manager = CryptoManager::get_instance();
204     crypto_manager.lock().unwrap().remove_need_device_unlocked();
205 }
206 
207 lazy_static! {
208     static ref RECORD_TIME: Mutex<Option<Instant>> = Mutex::new(None);
209 }
210 
backup_db_sync()211 async fn backup_db_sync() {
212     let _counter_user = AutoCounter::new();
213     let cur_time = Instant::now();
214     logi!("[INFO]Start backup db.");
215 
216     let mut record_time = RECORD_TIME.lock().expect("Failed to lock RECORD_TIME");
217 
218     let should_backup = match *record_time {
219         Some(ref last_time) => cur_time.duration_since(*last_time) > Duration::new(3600, 0),
220         None => true,
221     };
222 
223     if should_backup {
224         *record_time = Some(cur_time);
225         if let Err(e) = backup_all_db(&cur_time) {
226             let calling_info = CallingInfo::new_self();
227             upload_fault_system_event(&calling_info, cur_time, "backup_db", &e);
228         }
229     }
230     logi!("[INFO]Finish backup db.");
231 }
232 
backup_db()233 pub(crate) extern "C" fn backup_db() {
234     let _handle = ylong_runtime::spawn(backup_db_sync());
235 }
236 
on_app_restore(user_id: i32, bundle_name: *const u8, app_index: i32)237 pub(crate) extern "C" fn on_app_restore(user_id: i32, bundle_name: *const u8, app_index: i32) {
238     let c_str = unsafe { CStr::from_ptr(bundle_name as _) };
239     let bundle_name = match c_str.to_str() {
240         Ok(s) => s.to_string(),
241         Err(e) => {
242             loge!("[FATAL]Parse sting from bundle name failed, error is {}.", e);
243             return;
244         },
245     };
246     logi!("[INFO]On app -{}-{}- restore.", user_id, bundle_name);
247 
248     if let Ok(load) = AssetPlugin::get_instance().load_plugin() {
249         let mut params = ExtDbMap::new();
250         params.insert(PARAM_NAME_USER_ID, Value::Number(user_id as u32));
251         params.insert(PARAM_NAME_BUNDLE_NAME, Value::Bytes(bundle_name.as_bytes().to_vec()));
252         params.insert(PARAM_NAME_APP_INDEX, Value::Number(app_index as u32));
253         match load.process_event(EventType::OnAppRestore, &params) {
254             Ok(()) => logi!("process app restore event success."),
255             Err(code) => loge!("process app restore event failed, code: {}", code),
256         }
257     }
258 }
259 
on_user_unlocked(user_id: i32)260 pub(crate) extern "C" fn on_user_unlocked(user_id: i32) {
261     logi!("[INFO]On user -{}- unlocked.", user_id);
262 
263     // Trigger upgrading de db version and key alias
264     match trigger_db_upgrade(user_id, false) {
265         Ok(()) => logi!("upgrade de db version and key alias on user-unlocked success."),
266         Err(e) => loge!("upgrade de db version and key alias on user-unlocked failed, err is: {}", e),
267     }
268 
269     // Trigger upgrading ce db version and key alias
270     match trigger_db_upgrade(user_id, true) {
271         Ok(()) => logi!("upgrade ce db version and key alias on user-unlocked success."),
272         Err(e) => loge!("upgrade ce db version and key alias on user-unlocked failed, err is: {}", e),
273     }
274 
275     if let Ok(load) = AssetPlugin::get_instance().load_plugin() {
276         let mut params = ExtDbMap::new();
277         params.insert(PARAM_NAME_USER_ID, Value::Number(user_id as u32));
278         match load.process_event(EventType::OnUserUnlocked, &params) {
279             Ok(()) => logi!("process user unlocked event success."),
280             Err(code) => loge!("process user unlocked event failed, code: {}", code),
281         }
282     }
283 }
284 
notify_on_user_removed(user_id: i32)285 pub(crate) fn notify_on_user_removed(user_id: i32) {
286     logi!("[INFO]On user remove [{}].", user_id);
287 
288     if let Ok(load) = AssetPlugin::get_instance().load_plugin() {
289         let mut params = ExtDbMap::new();
290         params.insert(PARAM_NAME_USER_ID, Value::Number(user_id as u32));
291         match load.process_event(EventType::OnUserRemoved, &params) {
292             Ok(()) => logi!("process user removed event success."),
293             Err(code) => loge!("process user removed event failed, code: {}", code),
294         }
295     }
296 }
297 
on_schedule_wakeup()298 pub(crate) extern "C" fn on_schedule_wakeup() {
299     logi!("[INFO]On SA wakes up at a scheduled time(36H).");
300     let default_user_id = 0;
301     let self_bundle_name = "asset_service";
302 
303     if let Ok(load) = AssetPlugin::get_instance().load_plugin() {
304         let mut params = ExtDbMap::new();
305         params.insert(PARAM_NAME_USER_ID, Value::Number(default_user_id as u32));
306         params.insert(PARAM_NAME_BUNDLE_NAME, Value::Bytes(self_bundle_name.as_bytes().to_vec()));
307         match load.process_event(EventType::Sync, &params) {
308             Ok(()) => logi!("process sync ext event success."),
309             Err(code) => loge!("process sync ext event failed, code: {}", code),
310         }
311     }
312 }
313 
backup_de_db_if_accessible(entry: &DirEntry, user_id: i32) -> Result<()>314 fn backup_de_db_if_accessible(entry: &DirEntry, user_id: i32) -> Result<()> {
315     for db_path in fs::read_dir(format!("{}", entry.path().to_string_lossy()))? {
316         let db_path = db_path?;
317         let db_name = db_path.file_name().to_string_lossy().to_string();
318         if db_name.ends_with(DB_SUFFIX) {
319             let from_path = db_path.path().to_string_lossy().to_string();
320             Database::check_db_accessible(from_path.clone(), user_id, db_name.clone(), None)?;
321             let backup_path = format!("{}{}", from_path, BACKUP_SUFFIX);
322             fs::copy(from_path, backup_path)?;
323         }
324     }
325     Ok(())
326 }
327 
backup_ce_db_if_accessible(user_id: i32) -> Result<()>328 fn backup_ce_db_if_accessible(user_id: i32) -> Result<()> {
329     if user_id < MINIMUM_MAIN_USER_ID {
330         return Ok(());
331     }
332     let ce_path = format!("{}/{}/asset_service", CE_ROOT_PATH, user_id);
333     for db_path in fs::read_dir(ce_path)? {
334         let db_path = db_path?;
335         let db_name = db_path.file_name().to_string_lossy().to_string();
336         if db_name.ends_with(DB_SUFFIX) {
337             let from_path = db_path.path().to_string_lossy().to_string();
338             let db_key = DbKey::get_db_key(user_id)?;
339             Database::check_db_accessible(from_path.clone(), user_id, db_name.clone(), Some(&db_key))?;
340             let backup_path = format!("{}{}", from_path, BACKUP_SUFFIX);
341             fs::copy(from_path, backup_path)?;
342         }
343     }
344 
345     Ok(())
346 }
347 
348 extern "C" {
GetUserIds(userIdsPtr: *mut i32, userIdsSize: *mut u32) -> i32349     fn GetUserIds(userIdsPtr: *mut i32, userIdsSize: *mut u32) -> i32;
GetUsersSize(userIdsSize: *mut u32) -> i32350     fn GetUsersSize(userIdsSize: *mut u32) -> i32;
351 }
352 
backup_all_db(start_time: &Instant) -> Result<()>353 fn backup_all_db(start_time: &Instant) -> Result<()> {
354     // Backup all de db if accessible.
355     for entry in fs::read_dir(DE_ROOT_PATH)? {
356         let entry = entry?;
357         if let Ok(user_id) = entry.file_name().to_string_lossy().to_string().parse::<i32>() {
358             if let Err(e) = backup_de_db_if_accessible(&entry, user_id) {
359                 let calling_info = CallingInfo::new_self();
360                 upload_fault_system_event(&calling_info, *start_time, &format!("backup_de_db_{}", user_id), &e);
361             }
362         }
363     }
364 
365     // Backup all ce db if accessible.
366     let mut user_ids_size: u32 = 0;
367     let user_ids_size_ptr = &mut user_ids_size;
368     let mut ret: i32;
369     unsafe {
370         ret = GetUsersSize(user_ids_size_ptr);
371     }
372     if ret != SUCCESS {
373         return log_throw_error!(ErrCode::AccountError, "[FATAL][SA]Get users size failed.");
374     }
375 
376     let mut user_ids: Vec<i32> = vec![0i32; (*user_ids_size_ptr + USER_ID_VEC_BUFFER).try_into().unwrap()];
377     let user_ids_ptr = user_ids.as_mut_ptr();
378     unsafe {
379         ret = GetUserIds(user_ids_ptr, user_ids_size_ptr);
380     }
381     if ret != SUCCESS {
382         return log_throw_error!(ErrCode::AccountError, "[FATAL][SA]Get user IDs failed.");
383     }
384 
385     let user_ids_slice;
386     unsafe {
387         user_ids_slice = slice::from_raw_parts_mut(user_ids_ptr, (*user_ids_size_ptr).try_into().unwrap());
388     }
389     for user_id in user_ids_slice.iter() {
390         if let Err(e) = backup_ce_db_if_accessible(*user_id) {
391             let calling_info = CallingInfo::new_self();
392             upload_fault_system_event(&calling_info, *start_time, &format!("backup_ce_db_{}", *user_id), &e);
393         }
394     }
395 
396     Ok(())
397 }
398 
399 #[derive(Clone)]
400 #[repr(C)]
401 struct EventCallBack {
402     on_package_remove: extern "C" fn(i32, *const u8, u32, *const u8, i32),
403     on_user_removed: extern "C" fn(i32),
404     on_screen_off: extern "C" fn(),
405     on_charging: extern "C" fn(),
406     on_app_restore: extern "C" fn(i32, *const u8, i32),
407     on_user_unlocked: extern "C" fn(i32),
408 }
409 
410 extern "C" {
SubscribeSystemEvent(eventCallBack: EventCallBack) -> bool411     fn SubscribeSystemEvent(eventCallBack: EventCallBack) -> bool;
UnSubscribeSystemEvent() -> bool412     fn UnSubscribeSystemEvent() -> bool;
413 }
414 
415 /// Subscribe to the add and remove events of system abilities.
subscribe()416 pub(crate) fn subscribe() {
417     unsafe {
418         let call_back = EventCallBack {
419             on_package_remove: on_package_removed,
420             on_user_removed,
421             on_screen_off: delete_crypto_need_unlock,
422             on_charging: backup_db,
423             on_app_restore,
424             on_user_unlocked,
425         };
426         if SubscribeSystemEvent(call_back.clone()) {
427             logi!("Subscribe system event success.");
428         } else {
429             loge!("Subscribe system event failed.")
430         }
431     }
432 }
433 
434 /// Unsubscribe to the add and remove events of system abilities.
unsubscribe()435 pub(crate) fn unsubscribe() {
436     unsafe {
437         if !UnSubscribeSystemEvent() {
438             loge!("Unsubscribe system event failed.")
439         }
440     }
441 }
442