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