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::sync::atomic::{AtomicBool, AtomicI32, Ordering};
15 use std::sync::{Mutex, Once};
16 
17 pub(crate) use ffi::*;
18 
19 use super::database::RequestDb;
20 use crate::manage::events::TaskManagerEvent;
21 use crate::manage::task_manager::TaskManagerTx;
22 use crate::utils::runtime_spawn;
23 
24 #[derive(Debug)]
25 pub(crate) enum AccountEvent {
26     Remove(i32),
27     Changed,
28 }
29 
30 pub(crate) static FOREGROUND_ACCOUNT: AtomicI32 = AtomicI32::new(0);
31 pub(crate) static BACKGROUND_ACCOUNTS: Mutex<Option<Vec<i32>>> = Mutex::new(None);
32 static UPDATE_FLAG: AtomicBool = AtomicBool::new(false);
33 static mut TASK_MANAGER_TX: Option<TaskManagerTx> = None;
34 
remove_account_tasks(user_id: i32)35 pub(crate) fn remove_account_tasks(user_id: i32) {
36     info!("delete database task, uid {}", user_id);
37     let request_db = RequestDb::get_instance();
38     request_db.delete_all_account_tasks(user_id);
39 }
40 
update_accounts(task_manager: TaskManagerTx)41 pub(crate) fn update_accounts(task_manager: TaskManagerTx) {
42     if UPDATE_FLAG
43         .compare_exchange(false, true, Ordering::SeqCst, Ordering::SeqCst)
44         .is_ok()
45     {
46         runtime_spawn(AccountUpdater::new(task_manager).update());
47     }
48 }
49 
50 struct AccountUpdater {
51     change_flag: bool,
52     task_manager: TaskManagerTx,
53 }
54 
55 impl AccountUpdater {
new(task_manager: TaskManagerTx) -> Self56     fn new(task_manager: TaskManagerTx) -> Self {
57         Self {
58             change_flag: false,
59             task_manager,
60         }
61     }
62 
63     #[cfg_attr(not(feature = "oh"), allow(unused))]
update(mut self)64     async fn update(mut self) {
65         info!("AccountUpdate Start");
66         let old_foreground = FOREGROUND_ACCOUNT.load(Ordering::SeqCst);
67         let old_background = BACKGROUND_ACCOUNTS.lock().unwrap().clone();
68 
69         #[cfg(feature = "oh")]
70         if let Some(foreground_account) = get_foreground_account().await {
71             if old_foreground != foreground_account {
72                 self.change_flag = true;
73                 FOREGROUND_ACCOUNT.store(foreground_account, Ordering::SeqCst);
74             }
75         }
76 
77         #[cfg(feature = "oh")]
78         if let Some(background_accounts) = get_background_accounts().await {
79             if !old_background.is_some_and(|old_background| old_background == background_accounts) {
80                 self.change_flag = true;
81                 *BACKGROUND_ACCOUNTS.lock().unwrap() = Some(background_accounts);
82             }
83         }
84     }
85 }
86 
87 impl Drop for AccountUpdater {
drop(&mut self)88     fn drop(&mut self) {
89         info!("AccountUpdate Finished");
90         UPDATE_FLAG.store(false, Ordering::SeqCst);
91         if self.change_flag {
92             info!("AccountInfo changed, notify task manager");
93             self.task_manager
94                 .send_event(TaskManagerEvent::Account(AccountEvent::Changed));
95         }
96     }
97 }
98 
99 #[cfg(feature = "oh")]
get_foreground_account() -> Option<i32>100 async fn get_foreground_account() -> Option<i32> {
101     let mut foreground_account = 0;
102     for i in 0..10 {
103         let res = GetForegroundOsAccount(&mut foreground_account);
104         if res == 0 {
105             return Some(foreground_account);
106         } else {
107             error!("GetForegroundOsAccount failed: {} retry {} times", res, i);
108             ylong_runtime::time::sleep(std::time::Duration::from_millis(500)).await;
109         }
110     }
111     None
112 }
113 
114 #[cfg(feature = "oh")]
get_background_accounts() -> Option<Vec<i32>>115 async fn get_background_accounts() -> Option<Vec<i32>> {
116     for i in 0..10 {
117         let mut accounts = vec![];
118         let res = GetBackgroundOsAccounts(&mut accounts);
119         if res == 0 {
120             return Some(accounts);
121         } else {
122             error!("GetBackgroundOsAccounts failed: {} retry {} times", res, i);
123             ylong_runtime::time::sleep(std::time::Duration::from_millis(500)).await;
124         }
125     }
126     None
127 }
128 
129 #[cfg(feature = "oh")]
registry_account_subscribe(task_manager: TaskManagerTx)130 pub(crate) fn registry_account_subscribe(task_manager: TaskManagerTx) {
131     static ONCE: Once = Once::new();
132 
133     ONCE.call_once(|| unsafe {
134         TASK_MANAGER_TX = Some(task_manager.clone());
135     });
136 
137     info!("registry_account_subscribe");
138 
139     loop {
140         let ret = RegistryAccountSubscriber(
141             OS_ACCOUNT_SUBSCRIBE_TYPE::SWITCHED,
142             Box::new(task_manager.clone()),
143             |_, _| {},
144             |_new_id, _old_id, task_manager| update_accounts(task_manager.clone()),
145         );
146 
147         if ret != 0 {
148             error!(
149                 "registry_account_switch_subscribe  failed: {} retry 500ms later",
150                 ret
151             );
152             std::thread::sleep(std::time::Duration::from_millis(500));
153         } else {
154             break;
155         }
156     }
157 
158     loop {
159         let ret = RegistryAccountSubscriber(
160             OS_ACCOUNT_SUBSCRIBE_TYPE::ACTIVED,
161             Box::new(task_manager.clone()),
162             |_id, task_manager| update_accounts(task_manager.clone()),
163             |_, _, _| {},
164         );
165 
166         if ret != 0 {
167             error!(
168                 "registry_account_active_subscribe failed: {} retry 500ms later",
169                 ret
170             );
171             std::thread::sleep(std::time::Duration::from_millis(500));
172         } else {
173             break;
174         }
175     }
176 
177     loop {
178         let ret = RegistryAccountSubscriber(
179             OS_ACCOUNT_SUBSCRIBE_TYPE::REMOVED,
180             Box::new(task_manager.clone()),
181             |id, task_manager| {
182                 task_manager.send_event(TaskManagerEvent::Account(AccountEvent::Remove(*id)));
183             },
184             |_, _, _| {},
185         );
186 
187         if ret != 0 {
188             error!(
189                 "registry_account_remove_subscribe failed: {} retry 500ms later",
190                 ret
191             );
192             std::thread::sleep(std::time::Duration::from_millis(500));
193         } else {
194             break;
195         }
196     }
197 
198     loop {
199         let ret = RegistryAccountSubscriber(
200             OS_ACCOUNT_SUBSCRIBE_TYPE::STOPPED,
201             Box::new(task_manager.clone()),
202             |_id, task_manager| update_accounts(task_manager.clone()),
203             |_, _, _| {},
204         );
205 
206         if ret != 0 {
207             error!(
208                 "registry_account_stop_subscribe failed: {} retry 500ms later",
209                 ret
210             );
211             std::thread::sleep(std::time::Duration::from_millis(500));
212         } else {
213             break;
214         }
215     }
216 
217     update_accounts(task_manager.clone());
218 }
219 
220 impl RequestDb {
delete_all_account_tasks(&self, user_id: i32)221     pub(crate) fn delete_all_account_tasks(&self, user_id: i32) {
222         let sql = format!("DELETE from request_task WHERE uid/200000 = {}", user_id);
223         if let Err(e) = self.execute(&sql) {
224             error!("delete_all_account_tasks failed: {}", e);
225         };
226     }
227 }
228 
229 #[cxx::bridge(namespace = "OHOS::Request")]
230 mod ffi {
231     #[repr(i32)]
232     enum OS_ACCOUNT_SUBSCRIBE_TYPE {
233         INVALID_TYPE = -1,
234         ACTIVED = 0,
235         ACTIVATING,
236         UNLOCKED,
237         CREATED,
238         REMOVED,
239         STOPPING,
240         STOPPED,
241         SWITCHING,
242         SWITCHED,
243     }
244 
245     extern "Rust" {
246         type TaskManagerTx;
247     }
248 
249     unsafe extern "C++" {
250         include!("account.h");
251         include!("os_account_subscribe_info.h");
252         include!("c_request_database.h");
253 
254         type OS_ACCOUNT_SUBSCRIBE_TYPE;
GetForegroundOsAccount(account: &mut i32) -> i32255         fn GetForegroundOsAccount(account: &mut i32) -> i32;
GetBackgroundOsAccounts(accounts: &mut Vec<i32>) -> i32256         fn GetBackgroundOsAccounts(accounts: &mut Vec<i32>) -> i32;
257 
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), ) -> i32258         fn RegistryAccountSubscriber(
259             subscribe_type: OS_ACCOUNT_SUBSCRIBE_TYPE,
260             task_manager: Box<TaskManagerTx>,
261             on_accounts_changed: fn(&i32, task_manager: &TaskManagerTx),
262             on_accounts_switch: fn(&i32, &i32, task_manager: &TaskManagerTx),
263         ) -> i32;
264 
GetOhosAccountUid() -> String265         fn GetOhosAccountUid() -> String;
266     }
267 }
268 
269 #[cfg(feature = "oh")]
270 #[cfg(test)]
271 mod test {
272     use ylong_runtime::sync::mpsc;
273 
274     use super::*;
275     use crate::tests::test_init;
276 
277     #[test]
ut_account_check_oh()278     fn ut_account_check_oh() {
279         test_init();
280 
281         assert_eq!(0, FOREGROUND_ACCOUNT.load(Ordering::SeqCst));
282         assert!(BACKGROUND_ACCOUNTS.lock().unwrap().is_none());
283 
284         let (tx, mut rx) = mpsc::unbounded_channel();
285         let task_manager = TaskManagerTx { tx };
286         registry_account_subscribe(task_manager);
287         ylong_runtime::block_on(async {
288             let msg = rx.recv().await.unwrap();
289             assert!(matches!(
290                 msg,
291                 TaskManagerEvent::Account(AccountEvent::Changed)
292             ));
293             assert_ne!(FOREGROUND_ACCOUNT.load(Ordering::SeqCst), 0);
294             assert!(BACKGROUND_ACCOUNTS.lock().unwrap().is_some());
295         })
296     }
297 
298     #[test]
ut_account_update()299     fn ut_account_update() {
300         test_init();
301         ylong_runtime::block_on(async {
302             let (tx, mut rx) = mpsc::unbounded_channel();
303             let task_manager = TaskManagerTx { tx };
304             let updater = AccountUpdater::new(task_manager.clone());
305             drop(updater);
306             ylong_runtime::time::sleep(std::time::Duration::from_secs(2)).await;
307             assert!(rx.is_empty());
308             let mut updater = AccountUpdater::new(task_manager);
309             updater.change_flag = true;
310             drop(updater);
311             let msg = rx.recv().await.unwrap();
312             assert!(matches!(
313                 msg,
314                 TaskManagerEvent::Account(AccountEvent::Changed)
315             ));
316         })
317     }
318 
319     #[test]
ut_account_update_branch()320     fn ut_account_update_branch() {
321         let old_background = Option::<Vec<i32>>::None;
322         let background_accounts = vec![100];
323         assert!(!old_background.is_some_and(|old_background| old_background == background_accounts));
324         let old_background = Option::<Vec<i32>>::Some(vec![101]);
325         assert!(!old_background.is_some_and(|old_background| old_background == background_accounts));
326         let old_background = Option::<Vec<i32>>::Some(vec![100]);
327         assert!(old_background.is_some_and(|old_background| old_background == background_accounts));
328     }
329 }
330