1 /*
2 * Copyright (C) 2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "data_connection_monitor.h"
17
18 #include "core_manager_inner.h"
19 #include "radio_event.h"
20 #include "telephony_log_wrapper.h"
21
22 #include "cellular_data_event_code.h"
23 #include "cellular_data_hisysevent.h"
24 #include "cellular_data_service.h"
25 #include "cellular_data_types.h"
26 #include "cellular_data_constant.h"
27 #include "data_service_ext_wrapper.h"
28 #include "telephony_ext_wrapper.h"
29
30 #ifdef ABILITY_POWER_SUPPORT
31 #include "power_mgr_client.h"
32 #endif
33
34 namespace OHOS {
35 namespace Telephony {
DataConnectionMonitor(int32_t slotId)36 DataConnectionMonitor::DataConnectionMonitor(int32_t slotId) : TelEventHandler("DataConnectionMonitor"), slotId_(slotId)
37 {
38 trafficManager_ = std::make_unique<TrafficManagement>(slotId);
39 stallDetectionTrafficManager_ = std::make_unique<TrafficManagement>(slotId);
40 if (trafficManager_ == nullptr || stallDetectionTrafficManager_ == nullptr) {
41 TELEPHONY_LOGE("TrafficManager or stallDetectionTrafficManager init failed");
42 }
43 }
44
HandleScreenStateChanged(bool isScreenOn)45 void DataConnectionMonitor::HandleScreenStateChanged(bool isScreenOn)
46 {
47 if (isScreenOn_ == isScreenOn) {
48 return;
49 }
50 isScreenOn_ = isScreenOn;
51 const int32_t defSlotId = CoreManagerInner::GetInstance().GetDefaultCellularDataSlotId();
52 if (slotId_ != defSlotId && !IsVsimEnabled()) {
53 return;
54 }
55 StopStallDetectionTimer();
56 StartStallDetectionTimer();
57 }
58
IsVsimEnabled()59 bool DataConnectionMonitor::IsVsimEnabled()
60 {
61 #ifdef OHOS_BUILD_ENABLE_TELEPHONY_EXT
62 if (TELEPHONY_EXT_WRAPPER.getVSimSlotId_ && TELEPHONY_EXT_WRAPPER.isVSimEnabled_) {
63 int vSimSlotId = INVALID_SLOT_ID;
64 TELEPHONY_EXT_WRAPPER.getVSimSlotId_(vSimSlotId);
65 if (vSimSlotId == slotId_ && TELEPHONY_EXT_WRAPPER.isVSimEnabled_()) {
66 return true;
67 }
68 }
69 #endif
70 return false;
71 }
72
IsAggressiveRecovery()73 bool DataConnectionMonitor::IsAggressiveRecovery()
74 {
75 return (dataRecoveryState_ == RecoveryState::STATE_CLEANUP_CONNECTIONS) ||
76 (dataRecoveryState_ == RecoveryState::STATE_REREGISTER_NETWORK) ||
77 (dataRecoveryState_ == RecoveryState::STATE_RADIO_STATUS_RESTART);
78 }
79
GetStallDetectionPeriod()80 int32_t DataConnectionMonitor::GetStallDetectionPeriod()
81 {
82 if (isScreenOn_ || IsAggressiveRecovery()) {
83 return DATA_STALL_ALARM_AGGRESSIVE_DELAY_IN_MS_DEFAULT;
84 }
85 return DATA_STALL_ALARM_NON_AGGRESSIVE_DELAY_IN_MS_DEFAULT;
86 }
87
StartStallDetectionTimer()88 void DataConnectionMonitor::StartStallDetectionTimer()
89 {
90 TELEPHONY_LOGI("Slot%{public}d: start stall detection", slotId_);
91 stallDetectionEnabled_ = true;
92 int32_t stallDetectionPeriod = GetStallDetectionPeriod();
93 TELEPHONY_LOGI("stallDetectionPeriod = %{public}d", stallDetectionPeriod);
94 if (!HasInnerEvent(CellularDataEventCode::MSG_STALL_DETECTION_EVENT_ID)) {
95 AppExecFwk::InnerEvent::Pointer event =
96 AppExecFwk::InnerEvent::Get(CellularDataEventCode::MSG_STALL_DETECTION_EVENT_ID);
97 SendEvent(event, stallDetectionPeriod, Priority::LOW);
98 }
99 }
100
OnStallDetectionTimer()101 __attribute__((no_sanitize("cfi"))) void DataConnectionMonitor::OnStallDetectionTimer()
102 {
103 TELEPHONY_LOGD("Slot%{public}d: on stall detection", slotId_);
104 #ifdef OHOS_BUILD_ENABLE_DATA_SERVICE_EXT
105 if (DATA_SERVICE_EXT_WRAPPER.requestTcpAndDnsPackets_) {
106 DATA_SERVICE_EXT_WRAPPER.requestTcpAndDnsPackets_();
107 return;
108 }
109 #endif
110 UpdateFlowInfo();
111 if (noRecvPackets_ > RECOVERY_TRIGGER_PACKET) {
112 HandleRecovery();
113 noRecvPackets_ = 0;
114 }
115 int32_t stallDetectionPeriod = GetStallDetectionPeriod();
116 TELEPHONY_LOGI("stallDetectionPeriod = %{public}d", stallDetectionPeriod);
117 if (!HasInnerEvent(CellularDataEventCode::MSG_STALL_DETECTION_EVENT_ID) && stallDetectionEnabled_) {
118 AppExecFwk::InnerEvent::Pointer event =
119 AppExecFwk::InnerEvent::Get(CellularDataEventCode::MSG_STALL_DETECTION_EVENT_ID);
120 SendEvent(event, stallDetectionPeriod, Priority::LOW);
121 }
122 }
123
StopStallDetectionTimer()124 void DataConnectionMonitor::StopStallDetectionTimer()
125 {
126 TELEPHONY_LOGD("Slot%{public}d: stop stall detection", slotId_);
127 stallDetectionEnabled_ = false;
128 RemoveEvent(CellularDataEventCode::MSG_STALL_DETECTION_EVENT_ID);
129 }
130
UpdateFlowInfo()131 void DataConnectionMonitor::UpdateFlowInfo()
132 {
133 if (stallDetectionTrafficManager_ == nullptr) {
134 TELEPHONY_LOGE("Slot%{public}d: stallDetectionTrafficManager_ is null", slotId_);
135 return;
136 }
137 int64_t previousSentPackets = 0;
138 int64_t previousRecvPackets = 0;
139 int64_t currentSentPackets = 0;
140 int64_t currentRecvPackets = 0;
141 stallDetectionTrafficManager_->GetPacketData(previousSentPackets, previousRecvPackets);
142 stallDetectionTrafficManager_->UpdatePacketData();
143 stallDetectionTrafficManager_->GetPacketData(currentSentPackets, currentRecvPackets);
144 int64_t sentPackets = currentSentPackets - previousSentPackets;
145 int64_t recvPackets = currentRecvPackets - previousRecvPackets;
146 if (sentPackets > 0 && recvPackets == 0) {
147 noRecvPackets_ += sentPackets;
148 } else if ((sentPackets > 0 && recvPackets > 0) || (sentPackets == 0 && recvPackets > 0)) {
149 noRecvPackets_ = 0;
150 dataRecoveryState_ = RecoveryState::STATE_REQUEST_CONTEXT_LIST;
151 } else {
152 TELEPHONY_LOGD("Slot%{public}d: Update Flow Info nothing to do", slotId_);
153 }
154 }
155
HandleRecovery()156 void DataConnectionMonitor::HandleRecovery()
157 {
158 if (callState_ != static_cast<int32_t>(TelCallStatus::CALL_STATUS_IDLE) &&
159 callState_ != static_cast<int32_t>(TelCallStatus::CALL_STATUS_DISCONNECTED)) {
160 TELEPHONY_LOGI("Slot%{public}d: Stop recovery while call is busy", slotId_);
161 dataRecoveryState_ = RecoveryState::STATE_REQUEST_CONTEXT_LIST;
162 return;
163 }
164 switch (dataRecoveryState_) {
165 case RecoveryState::STATE_REQUEST_CONTEXT_LIST: {
166 TELEPHONY_LOGI("Slot%{public}d: Handle Recovery: get data call list", slotId_);
167 dataRecoveryState_ = RecoveryState::STATE_CLEANUP_CONNECTIONS;
168 GetPdpContextList();
169 CellularDataHiSysEvent::WriteDataDeactiveBehaviorEvent(slotId_, DataDisconnectCause::ON_THE_NETWORK_SIDE);
170 break;
171 }
172 case RecoveryState::STATE_CLEANUP_CONNECTIONS: {
173 TELEPHONY_LOGI("Slot%{public}d: Handle Recovery: cleanup connections", slotId_);
174 dataRecoveryState_ = RecoveryState::STATE_REREGISTER_NETWORK;
175 int32_t ret = DelayedRefSingleton<CellularDataService>::GetInstance().ClearAllConnections(
176 slotId_, (int32_t) DisConnectionReason::REASON_RETRY_CONNECTION);
177 if (ret != static_cast<int32_t>(RequestNetCode::REQUEST_SUCCESS)) {
178 TELEPHONY_LOGE("Slot%{public}d: Handle Recovery: cleanup connections failed", slotId_);
179 }
180 break;
181 }
182 case RecoveryState::STATE_REREGISTER_NETWORK: {
183 TELEPHONY_LOGI("Slot%{public}d: Handle Recovery: re-register network", slotId_);
184 dataRecoveryState_ = RecoveryState::STATE_RADIO_STATUS_RESTART;
185 GetPreferredNetworkPara();
186 break;
187 }
188 case RecoveryState::STATE_RADIO_STATUS_RESTART: {
189 TELEPHONY_LOGI("Slot%{public}d: Handle Recovery: radio restart", slotId_);
190 dataRecoveryState_ = RecoveryState::STATE_REQUEST_CONTEXT_LIST;
191 int32_t ret = DelayedRefSingleton<CellularDataService>::GetInstance().ClearAllConnections(
192 slotId_, (int32_t)DisConnectionReason::REASON_RETRY_CONNECTION);
193 if (ret != static_cast<int32_t>(RequestNetCode::REQUEST_SUCCESS)) {
194 TELEPHONY_LOGE("Slot%{public}d: Handle Recovery: radio restart cleanup connections failed", slotId_);
195 }
196 SetRadioState(CORE_SERVICE_POWER_OFF, RadioEvent::RADIO_OFF);
197 break;
198 }
199 default: {
200 TELEPHONY_LOGE("Slot%{public}d: Handle Recovery is falsie", slotId_);
201 break;
202 }
203 }
204 }
205
BeginNetStatistics()206 void DataConnectionMonitor::BeginNetStatistics()
207 {
208 updateNetStat_ = true;
209 UpdateNetTrafficState();
210 }
211
UpdateCallState(int32_t state)212 void DataConnectionMonitor::UpdateCallState(int32_t state)
213 {
214 callState_ = state;
215 }
216
EndNetStatistics()217 void DataConnectionMonitor::EndNetStatistics()
218 {
219 RemoveEvent(CellularDataEventCode::MSG_RUN_MONITOR_TASK);
220 updateNetStat_ = false;
221 if (dataFlowType_ != CellDataFlowType::DATA_FLOW_TYPE_NONE) {
222 dataFlowType_ = CellDataFlowType::DATA_FLOW_TYPE_NONE;
223 StateNotification::GetInstance().OnUpDataFlowtype(slotId_, dataFlowType_);
224 }
225 }
226
UpdateNetTrafficState()227 void DataConnectionMonitor::UpdateNetTrafficState()
228 {
229 if (!HasInnerEvent(CellularDataEventCode::MSG_RUN_MONITOR_TASK) && updateNetStat_) {
230 UpdateDataFlowType();
231 AppExecFwk::InnerEvent::Pointer event =
232 AppExecFwk::InnerEvent::Get(CellularDataEventCode::MSG_RUN_MONITOR_TASK);
233 SendEvent(event, DEFAULT_NET_STATISTICS_PERIOD);
234 }
235 }
236
GetPdpContextList()237 void DataConnectionMonitor::GetPdpContextList()
238 {
239 CoreManagerInner::GetInstance().GetPdpContextList(slotId_,
240 RadioEvent::RADIO_DATA_CALL_LIST_CHANGED, shared_from_this());
241 }
242
SetRadioState(const int32_t & radioState,const int32_t & eventCode)243 void DataConnectionMonitor::SetRadioState(const int32_t &radioState, const int32_t &eventCode)
244 {
245 CoreManagerInner::GetInstance().SetRadioState(slotId_, eventCode, radioState, 0, shared_from_this());
246 }
247
GetPreferredNetworkPara()248 void DataConnectionMonitor::GetPreferredNetworkPara()
249 {
250 CoreManagerInner::GetInstance().GetPreferredNetworkPara(slotId_,
251 RadioEvent::RADIO_GET_PREFERRED_NETWORK_MODE, shared_from_this());
252 }
253
SetPreferredNetworkPara(const AppExecFwk::InnerEvent::Pointer & event)254 void DataConnectionMonitor::SetPreferredNetworkPara(const AppExecFwk::InnerEvent::Pointer &event)
255 {
256 std::shared_ptr<PreferredNetworkTypeInfo> preferredNetworkInfo = event->GetSharedObject<PreferredNetworkTypeInfo>();
257 if (preferredNetworkInfo == nullptr) {
258 TELEPHONY_LOGE("preferredNetworkInfo is null");
259 return;
260 }
261 int32_t networkType = preferredNetworkInfo->preferredNetworkType;
262 CoreManagerInner::GetInstance().SetPreferredNetworkPara(slotId_,
263 RadioEvent::RADIO_SET_PREFERRED_NETWORK_MODE, networkType, shared_from_this());
264 }
265
GetDataRecoveryState()266 RecoveryState DataConnectionMonitor::GetDataRecoveryState()
267 {
268 return dataRecoveryState_;
269 }
270
UpdateDataFlowType()271 void DataConnectionMonitor::UpdateDataFlowType()
272 {
273 if (trafficManager_ == nullptr) {
274 TELEPHONY_LOGE("Slot%{public}d: trafficManager is null", slotId_);
275 return;
276 }
277 int64_t previousSentPackets = 0;
278 int64_t previousRecvPackets = 0;
279 int64_t currentSentPackets = 0;
280 int64_t currentRecvPackets = 0;
281 trafficManager_->GetPacketData(previousSentPackets, previousRecvPackets);
282 trafficManager_->UpdatePacketData();
283 trafficManager_->GetPacketData(currentSentPackets, currentRecvPackets);
284 int64_t sentPackets = currentSentPackets - previousSentPackets;
285 int64_t recvPackets = currentRecvPackets - previousRecvPackets;
286 CellDataFlowType previousDataFlowType = dataFlowType_;
287 if (previousSentPackets != 0 || previousRecvPackets != 0) {
288 if (sentPackets > 0 && recvPackets == 0) {
289 dataFlowType_ = CellDataFlowType::DATA_FLOW_TYPE_UP;
290 } else if (sentPackets == 0 && recvPackets > 0) {
291 dataFlowType_ = CellDataFlowType::DATA_FLOW_TYPE_DOWN;
292 } else if (sentPackets > 0 && recvPackets > 0) {
293 dataFlowType_ = CellDataFlowType::DATA_FLOW_TYPE_UP_DOWN;
294 } else {
295 dataFlowType_ = CellDataFlowType::DATA_FLOW_TYPE_NONE;
296 }
297 }
298 if (previousDataFlowType != dataFlowType_) {
299 StateNotification::GetInstance().OnUpDataFlowtype(slotId_, dataFlowType_);
300 }
301 }
302
GetDataFlowType()303 CellDataFlowType DataConnectionMonitor::GetDataFlowType()
304 {
305 return dataFlowType_;
306 }
307
SetDataFlowType(CellDataFlowType dataFlowType)308 void DataConnectionMonitor::SetDataFlowType(CellDataFlowType dataFlowType)
309 {
310 if (dataFlowType_ != dataFlowType) {
311 dataFlowType_ = dataFlowType;
312 StateNotification::GetInstance().OnUpDataFlowtype(slotId_, dataFlowType_);
313 }
314 }
315
IsNeedDoRecovery(bool needDoRecovery)316 void DataConnectionMonitor::IsNeedDoRecovery(bool needDoRecovery)
317 {
318 if (needDoRecovery) {
319 HandleRecovery();
320 } else {
321 dataRecoveryState_ = RecoveryState::STATE_REQUEST_CONTEXT_LIST;
322 }
323 int32_t stallDetectionPeriod = GetStallDetectionPeriod();
324 TELEPHONY_LOGI("stallDetectionPeriod = %{public}d", stallDetectionPeriod);
325 if (!HasInnerEvent(CellularDataEventCode::MSG_STALL_DETECTION_EVENT_ID) && stallDetectionEnabled_) {
326 AppExecFwk::InnerEvent::Pointer event =
327 AppExecFwk::InnerEvent::Get(CellularDataEventCode::MSG_STALL_DETECTION_EVENT_ID);
328 SendEvent(event, stallDetectionPeriod, Priority::LOW);
329 }
330 }
331
ProcessEvent(const AppExecFwk::InnerEvent::Pointer & event)332 void DataConnectionMonitor::ProcessEvent(const AppExecFwk::InnerEvent::Pointer &event)
333 {
334 if (event == nullptr) {
335 TELEPHONY_LOGE("Slot%{public}d: event is null", slotId_);
336 return;
337 }
338 uint32_t eventID = event->GetInnerEventId();
339 switch (eventID) {
340 case CellularDataEventCode::MSG_RUN_MONITOR_TASK: {
341 UpdateNetTrafficState();
342 break;
343 }
344 case CellularDataEventCode::MSG_STALL_DETECTION_EVENT_ID:
345 OnStallDetectionTimer();
346 break;
347 case RadioEvent::RADIO_DATA_CALL_LIST_CHANGED:
348 TELEPHONY_LOGI("Slot%{public}d: radio call list changed complete", slotId_);
349 break;
350 case RadioEvent::RADIO_GET_PREFERRED_NETWORK_MODE:
351 SetPreferredNetworkPara(event);
352 break;
353 case RadioEvent::RADIO_SET_PREFERRED_NETWORK_MODE:
354 TELEPHONY_LOGI("Slot%{public}d: set preferred network mode complete", slotId_);
355 break;
356 case RadioEvent::RADIO_OFF:
357 SetRadioState(CORE_SERVICE_POWER_ON, RadioEvent::RADIO_ON);
358 break;
359 case RadioEvent::RADIO_ON:
360 TELEPHONY_LOGI("Slot%{public}d: set radio state on complete", slotId_);
361 break;
362 default:
363 TELEPHONY_LOGI("Slot%{public}d: connection monitor ProcessEvent code = %{public}u", slotId_, eventID);
364 break;
365 }
366 }
367 } // namespace Telephony
368 } // namespace OHOS
369