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
27 namespace OHOS {
28 namespace Telephony {
DataConnectionMonitor(const std::shared_ptr<AppExecFwk::EventRunner> & runner,int32_t slotId)29 DataConnectionMonitor::DataConnectionMonitor(const std::shared_ptr<AppExecFwk::EventRunner> &runner, int32_t slotId)
30 : AppExecFwk::EventHandler(runner), slotId_(slotId)
31 {
32 trafficManager_ = std::make_unique<TrafficManagement>(slotId);
33 stallDetectionTrafficManager_ = std::make_unique<TrafficManagement>(slotId);
34 if (trafficManager_ == nullptr || stallDetectionTrafficManager_ == nullptr) {
35 TELEPHONY_LOGE("TrafficManager or stallDetectionTrafficManager init failed");
36 }
37 }
38
StartStallDetectionTimer()39 void DataConnectionMonitor::StartStallDetectionTimer()
40 {
41 TELEPHONY_LOGI("Slot%{public}d: start stall detection", slotId_);
42 stallDetectionEnabled = true;
43 if (!HasInnerEvent(CellularDataEventCode::MSG_STALL_DETECTION_EVENT_ID) && stallDetectionEnabled) {
44 AppExecFwk::InnerEvent::Pointer event =
45 AppExecFwk::InnerEvent::Get(CellularDataEventCode::MSG_STALL_DETECTION_EVENT_ID);
46 SendEvent(event, DEFAULT_STALL_DETECTION_PERIOD, Priority::LOW);
47 }
48 }
49
OnStallDetectionTimer()50 void DataConnectionMonitor::OnStallDetectionTimer()
51 {
52 TELEPHONY_LOGI("Slot%{public}d: on stall detection", slotId_);
53 UpdateFlowInfo();
54 if (noRecvPackets_ > RECOVERY_TRIGGER_PACKET) {
55 HandleRecovery();
56 noRecvPackets_ = 0;
57 }
58 if (!HasInnerEvent(CellularDataEventCode::MSG_STALL_DETECTION_EVENT_ID) && stallDetectionEnabled) {
59 AppExecFwk::InnerEvent::Pointer event =
60 AppExecFwk::InnerEvent::Get(CellularDataEventCode::MSG_STALL_DETECTION_EVENT_ID);
61 SendEvent(event, DEFAULT_STALL_DETECTION_PERIOD, Priority::LOW);
62 }
63 }
64
StopStallDetectionTimer()65 void DataConnectionMonitor::StopStallDetectionTimer()
66 {
67 TELEPHONY_LOGI("Slot%{public}d: stop stall detection", slotId_);
68 stallDetectionEnabled = false;
69 RemoveEvent(CellularDataEventCode::MSG_STALL_DETECTION_EVENT_ID);
70 }
71
UpdateFlowInfo()72 void DataConnectionMonitor::UpdateFlowInfo()
73 {
74 if (stallDetectionTrafficManager_ == nullptr) {
75 TELEPHONY_LOGE("Slot%{public}d: stallDetectionTrafficManager_ is null", slotId_);
76 return;
77 }
78 int64_t previousSentPackets = 0;
79 int64_t previousRecvPackets = 0;
80 int64_t currentSentPackets = 0;
81 int64_t currentRecvPackets = 0;
82 stallDetectionTrafficManager_->GetPacketData(previousSentPackets, previousRecvPackets);
83 stallDetectionTrafficManager_->UpdatePacketData();
84 stallDetectionTrafficManager_->GetPacketData(currentSentPackets, currentRecvPackets);
85 int64_t sentPackets = currentSentPackets - previousSentPackets;
86 int64_t recvPackets = currentRecvPackets - previousRecvPackets;
87 if (sentPackets > 0 && recvPackets == 0) {
88 noRecvPackets_ += sentPackets;
89 } else if ((sentPackets > 0 && recvPackets > 0) || (sentPackets == 0 && recvPackets > 0)) {
90 noRecvPackets_ = 0;
91 dataRecoveryState_ = RecoveryState::STATE_REQUEST_CONTEXT_LIST;
92 } else {
93 TELEPHONY_LOGE("Slot%{public}d: Update Flow Info nothing to do", slotId_);
94 }
95 }
96
HandleRecovery()97 void DataConnectionMonitor::HandleRecovery()
98 {
99 switch (dataRecoveryState_) {
100 case RecoveryState::STATE_REQUEST_CONTEXT_LIST: {
101 TELEPHONY_LOGI("Slot%{public}d: Handle Recovery: get data call list", slotId_);
102 dataRecoveryState_ = RecoveryState::STATE_CLEANUP_CONNECTIONS;
103 GetPdpContextList();
104 CellularDataHiSysEvent::WriteDataDeactiveBehaviorEvent(slotId_, DataDisconnectCause::ON_THE_NETWORK_SIDE);
105 break;
106 }
107 case RecoveryState::STATE_CLEANUP_CONNECTIONS: {
108 TELEPHONY_LOGI("Slot%{public}d: Handle Recovery: cleanup connections", slotId_);
109 dataRecoveryState_ = RecoveryState::STATE_REREGISTER_NETWORK;
110 int32_t ret = DelayedRefSingleton<CellularDataService>::GetInstance().ClearAllConnections(
111 slotId_, DisConnectionReason::REASON_RETRY_CONNECTION);
112 if (ret != static_cast<int32_t>(RequestNetCode::REQUEST_SUCCESS)) {
113 TELEPHONY_LOGE("Slot%{public}d: Handle Recovery: cleanup connections failed", slotId_);
114 }
115 break;
116 }
117 case RecoveryState::STATE_REREGISTER_NETWORK: {
118 TELEPHONY_LOGI("Slot%{public}d: Handle Recovery: re-register network", slotId_);
119 dataRecoveryState_ = RecoveryState::STATE_RADIO_STATUS_RESTART;
120 GetPreferredNetworkPara();
121 break;
122 }
123 case RecoveryState::STATE_RADIO_STATUS_RESTART: {
124 TELEPHONY_LOGI("Slot%{public}d: Handle Recovery: radio restart", slotId_);
125 dataRecoveryState_ = RecoveryState::STATE_REQUEST_CONTEXT_LIST;
126 int32_t ret = DelayedRefSingleton<CellularDataService>::GetInstance().ClearAllConnections(
127 slotId_, DisConnectionReason::REASON_RETRY_CONNECTION);
128 if (ret != static_cast<int32_t>(RequestNetCode::REQUEST_SUCCESS)) {
129 TELEPHONY_LOGE("Slot%{public}d: Handle Recovery: radio restart cleanup connections failed", slotId_);
130 }
131 SetRadioState(CORE_SERVICE_POWER_OFF, RadioEvent::RADIO_OFF);
132 break;
133 }
134 default: {
135 TELEPHONY_LOGE("Slot%{public}d: Handle Recovery is falsie", slotId_);
136 break;
137 }
138 }
139 }
140
BeginNetStatistics()141 void DataConnectionMonitor::BeginNetStatistics()
142 {
143 updateNetStat_ = true;
144 UpdateNetTrafficState();
145 }
146
EndNetStatistics()147 void DataConnectionMonitor::EndNetStatistics()
148 {
149 RemoveEvent(CellularDataEventCode::MSG_RUN_MONITOR_TASK);
150 updateNetStat_ = false;
151 if (dataFlowType_ != CellDataFlowType::DATA_FLOW_TYPE_NONE) {
152 dataFlowType_ = CellDataFlowType::DATA_FLOW_TYPE_NONE;
153 StateNotification::GetInstance().OnUpDataFlowtype(slotId_, dataFlowType_);
154 }
155 }
156
UpdateNetTrafficState()157 void DataConnectionMonitor::UpdateNetTrafficState()
158 {
159 if (!HasInnerEvent(CellularDataEventCode::MSG_RUN_MONITOR_TASK) && updateNetStat_) {
160 UpdateDataFlowType();
161 AppExecFwk::InnerEvent::Pointer event =
162 AppExecFwk::InnerEvent::Get(CellularDataEventCode::MSG_RUN_MONITOR_TASK);
163 SendEvent(event, DEFAULT_NET_STATISTICS_PERIOD);
164 }
165 }
166
GetPdpContextList()167 void DataConnectionMonitor::GetPdpContextList()
168 {
169 CoreManagerInner::GetInstance().GetPdpContextList(slotId_,
170 RadioEvent::RADIO_DATA_CALL_LIST_CHANGED, shared_from_this());
171 }
172
SetRadioState(const int32_t & radioState,const int32_t & eventCode)173 void DataConnectionMonitor::SetRadioState(const int32_t &radioState, const int32_t &eventCode)
174 {
175 CoreManagerInner::GetInstance().SetRadioState(slotId_, eventCode, radioState, 0, shared_from_this());
176 }
177
GetPreferredNetworkPara()178 void DataConnectionMonitor::GetPreferredNetworkPara()
179 {
180 CoreManagerInner::GetInstance().GetPreferredNetworkPara(slotId_,
181 RadioEvent::RADIO_GET_PREFERRED_NETWORK_MODE, shared_from_this());
182 }
183
SetPreferredNetworkPara(const AppExecFwk::InnerEvent::Pointer & event)184 void DataConnectionMonitor::SetPreferredNetworkPara(const AppExecFwk::InnerEvent::Pointer &event)
185 {
186 std::shared_ptr<PreferredNetworkTypeInfo> preferredNetworkInfo = event->GetSharedObject<PreferredNetworkTypeInfo>();
187 if (preferredNetworkInfo == nullptr) {
188 TELEPHONY_LOGE("preferredNetworkInfo is null");
189 return;
190 }
191 int32_t networkType = preferredNetworkInfo->preferredNetworkType;
192 CoreManagerInner::GetInstance().SetPreferredNetworkPara(slotId_,
193 RadioEvent::RADIO_SET_PREFERRED_NETWORK_MODE, networkType, shared_from_this());
194 }
195
UpdateDataFlowType()196 void DataConnectionMonitor::UpdateDataFlowType()
197 {
198 if (trafficManager_ == nullptr) {
199 TELEPHONY_LOGE("Slot%{public}d: trafficManager is null", slotId_);
200 return;
201 }
202 int64_t previousSentPackets = 0;
203 int64_t previousRecvPackets = 0;
204 int64_t currentSentPackets = 0;
205 int64_t currentRecvPackets = 0;
206 trafficManager_->GetPacketData(previousSentPackets, previousRecvPackets);
207 trafficManager_->UpdatePacketData();
208 trafficManager_->GetPacketData(currentSentPackets, currentRecvPackets);
209 int64_t sentPackets = currentSentPackets - previousSentPackets;
210 int64_t recvPackets = currentRecvPackets - previousRecvPackets;
211 CellDataFlowType previousDataFlowType = dataFlowType_;
212 if (previousSentPackets != 0 || previousRecvPackets != 0) {
213 if (sentPackets > 0 && recvPackets == 0) {
214 dataFlowType_ = CellDataFlowType::DATA_FLOW_TYPE_UP;
215 } else if (sentPackets == 0 && recvPackets > 0) {
216 dataFlowType_ = CellDataFlowType::DATA_FLOW_TYPE_DOWN;
217 } else if (sentPackets > 0 && recvPackets > 0) {
218 dataFlowType_ = CellDataFlowType::DATA_FLOW_TYPE_UP_DOWN;
219 } else {
220 dataFlowType_ = CellDataFlowType::DATA_FLOW_TYPE_NONE;
221 }
222 }
223 if (previousDataFlowType != dataFlowType_) {
224 StateNotification::GetInstance().OnUpDataFlowtype(slotId_, dataFlowType_);
225 }
226 }
227
GetDataFlowType()228 CellDataFlowType DataConnectionMonitor::GetDataFlowType()
229 {
230 return dataFlowType_;
231 }
232
SetDataFlowType(CellDataFlowType dataFlowType)233 void DataConnectionMonitor::SetDataFlowType(CellDataFlowType dataFlowType)
234 {
235 if (dataFlowType_ != dataFlowType) {
236 dataFlowType_ = dataFlowType;
237 StateNotification::GetInstance().OnUpDataFlowtype(slotId_, dataFlowType_);
238 }
239 }
240
ProcessEvent(const AppExecFwk::InnerEvent::Pointer & event)241 void DataConnectionMonitor::ProcessEvent(const AppExecFwk::InnerEvent::Pointer &event)
242 {
243 if (event == nullptr) {
244 TELEPHONY_LOGE("Slot%{public}d: event is null", slotId_);
245 return;
246 }
247 uint32_t eventID = event->GetInnerEventId();
248 switch (eventID) {
249 case CellularDataEventCode::MSG_RUN_MONITOR_TASK: {
250 UpdateNetTrafficState();
251 break;
252 }
253 case CellularDataEventCode::MSG_STALL_DETECTION_EVENT_ID:
254 OnStallDetectionTimer();
255 break;
256 case RadioEvent::RADIO_DATA_CALL_LIST_CHANGED:
257 TELEPHONY_LOGI("Slot%{public}d: radio call list changed complete", slotId_);
258 break;
259 case RadioEvent::RADIO_GET_PREFERRED_NETWORK_MODE:
260 SetPreferredNetworkPara(event);
261 break;
262 case RadioEvent::RADIO_SET_PREFERRED_NETWORK_MODE:
263 TELEPHONY_LOGI("Slot%{public}d: set preferred network mode complete", slotId_);
264 break;
265 case RadioEvent::RADIO_OFF:
266 SetRadioState(CORE_SERVICE_POWER_ON, RadioEvent::RADIO_ON);
267 break;
268 case RadioEvent::RADIO_ON:
269 TELEPHONY_LOGI("Slot%{public}d: set radio state on complete", slotId_);
270 break;
271 default:
272 TELEPHONY_LOGI("Slot%{public}d: connection monitor ProcessEvent code = %{public}u", slotId_, eventID);
273 break;
274 }
275 }
276 } // namespace Telephony
277 } // namespace OHOS
278