1 // Copyright (C) 2023 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 use std::sync::{Arc, RwLock};
14 
15 use cxx::UniquePtr;
16 use ffi::NetworkRegistry;
17 pub(crate) use ffi::{NetworkInfo, NetworkType};
18 use NetworkState::{Offline, Online};
19 
20 use crate::manage::network_manager::NetworkManager;
21 
22 cfg_oh! {
23     use super::events::TaskManagerEvent;
24     use super::task_manager::TaskManagerTx;
25 }
26 
27 #[derive(Clone)]
28 pub struct Network {
29     pub(crate) inner: NetworkInner,
30     #[cfg(feature = "oh")]
31     pub(crate) _registry: Option<Arc<UniquePtr<NetworkRegistry>>>,
32 }
33 
34 #[derive(Clone, Debug, PartialEq, Eq)]
35 pub(crate) enum NetworkState {
36     Offline,
37     Online(NetworkInfo),
38 }
39 
40 impl Network {
state(&self) -> NetworkState41     pub(crate) fn state(&self) -> NetworkState {
42         self.inner.state.read().unwrap().clone()
43     }
44 }
45 
register_network_change()46 pub(crate) fn register_network_change() {
47     const RETRY_TIME: i32 = if cfg!(test) { 1 } else { 20 };
48     let mut count: i32 = 0;
49     let mut network_manager = NetworkManager::get_instance().lock().unwrap();
50     let tx = network_manager.tx.clone();
51     if network_manager.network.state() != Offline {
52         return;
53     }
54     match tx {
55         Some(tx) => {
56             let mut registry: UniquePtr<NetworkRegistry> = UniquePtr::null();
57             while count < RETRY_TIME {
58                 registry = ffi::RegisterNetworkChange(
59                     Box::new(network_manager.network.inner.clone()),
60                     Box::new(NetworkTaskManagerTx { inner: tx.clone() }),
61                     |task_manager| {
62                         task_manager.inner.send_event(TaskManagerEvent::network());
63                     },
64                     |task_manager| {
65                         task_manager.inner.send_event(TaskManagerEvent::network());
66                     },
67                 );
68                 if registry.is_null() {
69                     std::thread::sleep(std::time::Duration::from_secs(1));
70                     count += 1;
71                     continue;
72                 }
73                 break;
74             }
75             if registry.is_null() {
76                 error!("RegisterNetworkChange failed!");
77                 return;
78             }
79             network_manager.network._registry = Some(Arc::new(registry));
80         }
81         None => {
82             error!("register_network_change failed, tx is None!");
83         }
84     }
85 }
86 
87 #[derive(Clone)]
88 pub struct NetworkInner {
89     state: Arc<RwLock<NetworkState>>,
90 }
91 
92 pub struct NetworkTaskManagerTx {
93     #[cfg(feature = "oh")]
94     inner: TaskManagerTx,
95 }
96 
97 impl NetworkInner {
new() -> Self98     pub(crate) fn new() -> Self {
99         Self {
100             state: Arc::new(RwLock::new(NetworkState::Offline)),
101         }
102     }
103 
notify_offline(&self)104     pub(crate) fn notify_offline(&self) {
105         let mut state = self.state.write().unwrap();
106         if *state != Offline {
107             info!("network is offline");
108             *state = Offline;
109         }
110     }
111 
notify_online(&self, info: NetworkInfo) -> bool112     pub(crate) fn notify_online(&self, info: NetworkInfo) -> bool {
113         let mut state = self.state.write().unwrap();
114         if !matches!(&*state, Online(old_info) if old_info == &info  ) {
115             info!("network online {:?}", info);
116             *state = Online(info.clone());
117             true
118         } else {
119             false
120         }
121     }
122 }
123 
124 unsafe impl Send for NetworkRegistry {}
125 unsafe impl Sync for NetworkRegistry {}
126 
127 #[allow(unreachable_pub)]
128 #[cxx::bridge(namespace = "OHOS::Request")]
129 mod ffi {
130 
131     #[derive(Clone, Eq, PartialEq, Debug)]
132     struct NetworkInfo {
133         network_type: NetworkType,
134         is_metered: bool,
135         is_roaming: bool,
136     }
137 
138     #[repr(u8)]
139     #[derive(Copy, Clone, Eq, PartialEq, Debug)]
140     enum NetworkType {
141         Other,
142         Wifi,
143         Cellular,
144     }
145 
146     extern "Rust" {
147         type NetworkInner;
148         type NetworkTaskManagerTx;
notify_online(self: &NetworkInner, info: NetworkInfo) -> bool149         fn notify_online(self: &NetworkInner, info: NetworkInfo) -> bool;
notify_offline(self: &NetworkInner)150         fn notify_offline(self: &NetworkInner);
151     }
152 
153     unsafe extern "C++" {
154         include!("network.h");
155         include!("c_request_database.h");
156         type NetworkRegistry;
RegisterNetworkChange( notifier: Box<NetworkInner>, task_manager: Box<NetworkTaskManagerTx>, notify_online: fn(&NetworkTaskManagerTx), notify_offline: fn(&NetworkTaskManagerTx), ) -> UniquePtr<NetworkRegistry>157         fn RegisterNetworkChange(
158             notifier: Box<NetworkInner>,
159             task_manager: Box<NetworkTaskManagerTx>,
160             notify_online: fn(&NetworkTaskManagerTx),
161             notify_offline: fn(&NetworkTaskManagerTx),
162         ) -> UniquePtr<NetworkRegistry>;
163     }
164 }
165