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, ¶ms) {
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, ¶ms) {
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, ¶ms) {
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, ¶ms) {
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, ¶ms) {
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