• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (C) 2024 Huawei Device Co., Ltd.
2 // Licensed under the Apache License, Version 2.0 (the "License");
3 // you may not use this file except in compliance with the License.
4 // You may obtain a copy of the License at
5 //
6 //     http://www.apache.org/licenses/LICENSE-2.0
7 //
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13 
14 use std::collections::HashSet;
15 use std::sync::atomic::{AtomicBool, AtomicI32, Ordering};
16 use std::sync::{Mutex, Once};
17 
18 pub(crate) use ffi::*;
19 
20 use super::database::RequestDb;
21 use crate::manage::events::TaskManagerEvent;
22 use crate::manage::task_manager::TaskManagerTx;
23 use crate::utils::{call_once, runtime_spawn};
24 
25 #[derive(Debug)]
26 pub(crate) enum AccountEvent {
27     Remove(i32),
28     Changed,
29 }
30 
31 pub(crate) static FOREGROUND_ACCOUNT: AtomicI32 = AtomicI32::new(0);
32 pub(crate) static BACKGROUND_ACCOUNTS: Mutex<Option<Vec<i32>>> = Mutex::new(None);
33 static UPDATE_FLAG: AtomicBool = AtomicBool::new(false);
34 static mut TASK_MANAGER_TX: Option<TaskManagerTx> = None;
35 
remove_account_tasks(user_id: i32)36 pub(crate) fn remove_account_tasks(user_id: i32) {
37     info!("delete database task, uid {}", user_id);
38     let request_db = RequestDb::get_instance();
39     request_db.delete_all_account_tasks(user_id);
40 }
41 
update_accounts(task_manager: TaskManagerTx)42 pub(crate) fn update_accounts(task_manager: TaskManagerTx) {
43     if UPDATE_FLAG
44         .compare_exchange(false, true, Ordering::SeqCst, Ordering::SeqCst)
45         .is_ok()
46     {
47         runtime_spawn(AccountUpdater::new(task_manager).update());
48     }
49 }
50 
query_active_accounts() -> (u64, HashSet<u64>)51 pub(crate) fn query_active_accounts() -> (u64, HashSet<u64>) {
52     let mut active_accounts = HashSet::new();
53     let foreground_account = FOREGROUND_ACCOUNT.load(Ordering::SeqCst) as u64;
54     active_accounts.insert(foreground_account);
55     if let Some(background_accounts) = BACKGROUND_ACCOUNTS.lock().unwrap().as_ref() {
56         for account in background_accounts.iter() {
57             active_accounts.insert(*account as u64);
58         }
59     }
60     (foreground_account, active_accounts)
61 }
62 
63 struct AccountUpdater {
64     change_flag: bool,
65     task_manager: TaskManagerTx,
66 }
67 
68 impl AccountUpdater {
new(task_manager: TaskManagerTx) -> Self69     fn new(task_manager: TaskManagerTx) -> Self {
70         Self {
71             change_flag: false,
72             task_manager,
73         }
74     }
75 
76     #[cfg_attr(not(feature = "oh"), allow(unused))]
update(mut self)77     async fn update(mut self) {
78         info!("AccountUpdate Start");
79         let old_foreground = FOREGROUND_ACCOUNT.load(Ordering::SeqCst);
80         let old_background = BACKGROUND_ACCOUNTS.lock().unwrap().clone();
81 
82         #[cfg(feature = "oh")]
83         if let Some(foreground_account) = get_foreground_account().await {
84             if old_foreground != foreground_account {
85                 self.change_flag = true;
86                 FOREGROUND_ACCOUNT.store(foreground_account, Ordering::SeqCst);
87             }
88         }
89 
90         #[cfg(feature = "oh")]
91         if let Some(background_accounts) = get_background_accounts().await {
92             if !old_background.is_some_and(|old_background| old_background == background_accounts) {
93                 self.change_flag = true;
94                 *BACKGROUND_ACCOUNTS.lock().unwrap() = Some(background_accounts);
95             }
96         }
97     }
98 }
99 
100 impl Drop for AccountUpdater {
drop(&mut self)101     fn drop(&mut self) {
102         info!("AccountUpdate Finished");
103         UPDATE_FLAG.store(false, Ordering::SeqCst);
104         if self.change_flag {
105             info!("AccountInfo changed, notify task manager");
106             self.task_manager
107                 .send_event(TaskManagerEvent::Account(AccountEvent::Changed));
108         }
109     }
110 }
111 
112 #[cfg(feature = "oh")]
get_foreground_account() -> Option<i32>113 async fn get_foreground_account() -> Option<i32> {
114     let mut foreground_account = 0;
115     for i in 0..10 {
116         let res = GetForegroundOsAccount(&mut foreground_account);
117         if res == 0 {
118             return Some(foreground_account);
119         } else {
120             error!("GetForegroundOsAccount failed: {} retry {} times", res, i);
121             sys_event!(
122                 ExecFault,
123                 DfxCode::OS_ACCOUNT_FAULT_01,
124                 &format!("GetForegroundOsAccount failed: {} retry {} times", res, i)
125             );
126             ylong_runtime::time::sleep(std::time::Duration::from_millis(500)).await;
127         }
128     }
129     None
130 }
131 
132 #[cfg(feature = "oh")]
get_background_accounts() -> Option<Vec<i32>>133 async fn get_background_accounts() -> Option<Vec<i32>> {
134     for i in 0..10 {
135         let mut accounts = vec![];
136         let res = GetBackgroundOsAccounts(&mut accounts);
137         if res == 0 {
138             return Some(accounts);
139         } else {
140             error!("GetBackgroundOsAccounts failed: {} retry {} times", res, i);
141             sys_event!(
142                 ExecFault,
143                 DfxCode::INVALID_IPC_MESSAGE_A00,
144                 &format!("GetBackgroundOsAccounts failed: {} retry {} times", res, i)
145             );
146 
147             ylong_runtime::time::sleep(std::time::Duration::from_millis(500)).await;
148         }
149     }
150     None
151 }
152 
153 #[cfg(feature = "oh")]
registry_account_subscribe(task_manager: TaskManagerTx)154 pub(crate) fn registry_account_subscribe(task_manager: TaskManagerTx) {
155     static ONCE: Once = Once::new();
156 
157     call_once(&ONCE, || unsafe {
158         TASK_MANAGER_TX = Some(task_manager.clone());
159     });
160 
161     info!("registry_account_subscribe");
162 
163     loop {
164         let ret = RegistryAccountSubscriber(
165             OS_ACCOUNT_SUBSCRIBE_TYPE::SWITCHED,
166             Box::new(task_manager.clone()),
167             |_, _| {},
168             |_new_id, _old_id, task_manager| update_accounts(task_manager.clone()),
169         );
170 
171         if ret != 0 {
172             error!(
173                 "registry_account_switch_subscribe failed: {} retry 500ms later",
174                 ret
175             );
176             sys_event!(
177                 ExecFault,
178                 DfxCode::OS_ACCOUNT_FAULT_00,
179                 &format!(
180                     "registry_account_switch_subscribe failed: {} retry 500ms later",
181                     ret
182                 )
183             );
184             std::thread::sleep(std::time::Duration::from_millis(500));
185         } else {
186             break;
187         }
188     }
189 
190     loop {
191         let ret = RegistryAccountSubscriber(
192             OS_ACCOUNT_SUBSCRIBE_TYPE::ACTIVATED,
193             Box::new(task_manager.clone()),
194             |_id, task_manager| update_accounts(task_manager.clone()),
195             |_, _, _| {},
196         );
197 
198         if ret != 0 {
199             error!(
200                 "registry_account_active_subscribe failed: {} retry 500ms later",
201                 ret
202             );
203             sys_event!(
204                 ExecFault,
205                 DfxCode::OS_ACCOUNT_FAULT_00,
206                 &format!(
207                     "registry_account_active_subscribe failed: {} retry 500ms later",
208                     ret
209                 )
210             );
211             std::thread::sleep(std::time::Duration::from_millis(500));
212         } else {
213             break;
214         }
215     }
216 
217     loop {
218         let ret = RegistryAccountSubscriber(
219             OS_ACCOUNT_SUBSCRIBE_TYPE::REMOVED,
220             Box::new(task_manager.clone()),
221             |id, task_manager| {
222                 task_manager.send_event(TaskManagerEvent::Account(AccountEvent::Remove(*id)));
223             },
224             |_, _, _| {},
225         );
226 
227         if ret != 0 {
228             error!(
229                 "registry_account_remove_subscribe failed: {} retry 500ms later",
230                 ret
231             );
232             sys_event!(
233                 ExecFault,
234                 DfxCode::OS_ACCOUNT_FAULT_00,
235                 &format!(
236                     "registry_account_remove_subscribe failed: {} retry 500ms later",
237                     ret
238                 )
239             );
240 
241             std::thread::sleep(std::time::Duration::from_millis(500));
242         } else {
243             break;
244         }
245     }
246 
247     loop {
248         let ret = RegistryAccountSubscriber(
249             OS_ACCOUNT_SUBSCRIBE_TYPE::STOPPED,
250             Box::new(task_manager.clone()),
251             |_id, task_manager| update_accounts(task_manager.clone()),
252             |_, _, _| {},
253         );
254 
255         if ret != 0 {
256             error!(
257                 "registry_account_stop_subscribe failed: {} retry 500ms later",
258                 ret
259             );
260             sys_event!(
261                 ExecFault,
262                 DfxCode::OS_ACCOUNT_FAULT_00,
263                 &format!(
264                     "registry_account_stop_subscribe failed: {} retry 500ms later",
265                     ret
266                 )
267             );
268 
269             std::thread::sleep(std::time::Duration::from_millis(500));
270         } else {
271             break;
272         }
273     }
274 
275     update_accounts(task_manager.clone());
276 }
277 
278 impl RequestDb {
delete_all_account_tasks(&self, user_id: i32)279     pub(crate) fn delete_all_account_tasks(&self, user_id: i32) {
280         let sql = format!("DELETE from request_task WHERE uid/200000 = {}", user_id);
281         if let Err(e) = self.execute(&sql) {
282             error!("delete_all_account_tasks failed: {}", e);
283             sys_event!(
284                 ExecFault,
285                 DfxCode::RDB_FAULT_04,
286                 &format!("delete_all_account_tasks failed: {}", e)
287             );
288         };
289     }
290 }
291 
292 #[cxx::bridge(namespace = "OHOS::Request")]
293 mod ffi {
294     #[repr(i32)]
295     enum OS_ACCOUNT_SUBSCRIBE_TYPE {
296         INVALID_TYPE = -1,
297         ACTIVATED = 0,
298         ACTIVATING,
299         UNLOCKED,
300         CREATED,
301         REMOVED,
302         STOPPING,
303         STOPPED,
304         SWITCHING,
305         SWITCHED,
306     }
307 
308     extern "Rust" {
309         type TaskManagerTx;
310     }
311 
312     unsafe extern "C++" {
313         include!("account.h");
314         include!("os_account_subscribe_info.h");
315         include!("c_request_database.h");
316 
317         type OS_ACCOUNT_SUBSCRIBE_TYPE;
GetForegroundOsAccount(account: &mut i32) -> i32318         fn GetForegroundOsAccount(account: &mut i32) -> i32;
GetBackgroundOsAccounts(accounts: &mut Vec<i32>) -> i32319         fn GetBackgroundOsAccounts(accounts: &mut Vec<i32>) -> i32;
320 
RegistryAccountSubscriber( subscribe_type: OS_ACCOUNT_SUBSCRIBE_TYPE, task_manager: Box<TaskManagerTx>, on_accounts_changed: fn(&i32, task_manager: &TaskManagerTx), on_accounts_switch: fn(&i32, &i32, task_manager: &TaskManagerTx), ) -> i32321         fn RegistryAccountSubscriber(
322             subscribe_type: OS_ACCOUNT_SUBSCRIBE_TYPE,
323             task_manager: Box<TaskManagerTx>,
324             on_accounts_changed: fn(&i32, task_manager: &TaskManagerTx),
325             on_accounts_switch: fn(&i32, &i32, task_manager: &TaskManagerTx),
326         ) -> i32;
327 
GetOhosAccountUid() -> String328         fn GetOhosAccountUid() -> String;
329     }
330 }
331 
332 #[cfg(feature = "oh")]
333 #[cfg(test)]
334 mod ut_account {
335     include!("../../tests/ut/manage/ut_account.rs");
336 }
337