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