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
29#ifdef ABILITY_POWER_SUPPORT
30#include "power_mgr_client.h"
31#endif
32
33namespace OHOS {
34namespace Telephony {
35DataConnectionMonitor::DataConnectionMonitor(int32_t slotId) : TelEventHandler("DataConnectionMonitor"), slotId_(slotId)
36{
37    trafficManager_ = std::make_unique<TrafficManagement>(slotId);
38    stallDetectionTrafficManager_ = std::make_unique<TrafficManagement>(slotId);
39    if (trafficManager_ == nullptr || stallDetectionTrafficManager_ == nullptr) {
40        TELEPHONY_LOGE("TrafficManager or stallDetectionTrafficManager init failed");
41    }
42}
43
44void DataConnectionMonitor::HandleScreenStateChanged(bool isScreenOn)
45{
46    if (isScreenOn_ == isScreenOn) {
47        return;
48    }
49    isScreenOn_ = isScreenOn;
50    StopStallDetectionTimer();
51    StartStallDetectionTimer();
52}
53
54bool DataConnectionMonitor::IsAggressiveRecovery()
55{
56    return (dataRecoveryState_ == RecoveryState::STATE_CLEANUP_CONNECTIONS) ||
57        (dataRecoveryState_ == RecoveryState::STATE_REREGISTER_NETWORK) ||
58        (dataRecoveryState_ == RecoveryState::STATE_RADIO_STATUS_RESTART);
59}
60
61int32_t DataConnectionMonitor::GetStallDetectionPeriod()
62{
63    if (isScreenOn_ || IsAggressiveRecovery()) {
64        return DATA_STALL_ALARM_AGGRESSIVE_DELAY_IN_MS_DEFAULT;
65    }
66    return DATA_STALL_ALARM_NON_AGGRESSIVE_DELAY_IN_MS_DEFAULT;
67}
68
69void DataConnectionMonitor::StartStallDetectionTimer()
70{
71    TELEPHONY_LOGI("Slot%{public}d: start stall detection", slotId_);
72    stallDetectionEnabled_ = true;
73    int32_t stallDetectionPeriod = GetStallDetectionPeriod();
74    TELEPHONY_LOGI("stallDetectionPeriod = %{public}d", stallDetectionPeriod);
75    if (!HasInnerEvent(CellularDataEventCode::MSG_STALL_DETECTION_EVENT_ID)) {
76        AppExecFwk::InnerEvent::Pointer event =
77            AppExecFwk::InnerEvent::Get(CellularDataEventCode::MSG_STALL_DETECTION_EVENT_ID);
78        SendEvent(event, stallDetectionPeriod, Priority::LOW);
79    }
80}
81
82__attribute__((no_sanitize("cfi"))) void DataConnectionMonitor::OnStallDetectionTimer()
83{
84    TELEPHONY_LOGD("Slot%{public}d: on stall detection", slotId_);
85#ifdef OHOS_BUILD_ENABLE_DATA_SERVICE_EXT
86    if (DATA_SERVICE_EXT_WRAPPER.requestTcpAndDnsPackets_) {
87        DATA_SERVICE_EXT_WRAPPER.requestTcpAndDnsPackets_();
88        return;
89    }
90#endif
91    UpdateFlowInfo();
92    if (noRecvPackets_ > RECOVERY_TRIGGER_PACKET) {
93        HandleRecovery();
94        noRecvPackets_ = 0;
95    }
96    int32_t stallDetectionPeriod = GetStallDetectionPeriod();
97    TELEPHONY_LOGI("stallDetectionPeriod = %{public}d", stallDetectionPeriod);
98    if (!HasInnerEvent(CellularDataEventCode::MSG_STALL_DETECTION_EVENT_ID) && stallDetectionEnabled_) {
99        AppExecFwk::InnerEvent::Pointer event =
100            AppExecFwk::InnerEvent::Get(CellularDataEventCode::MSG_STALL_DETECTION_EVENT_ID);
101        SendEvent(event, stallDetectionPeriod, Priority::LOW);
102    }
103}
104
105void DataConnectionMonitor::StopStallDetectionTimer()
106{
107    TELEPHONY_LOGD("Slot%{public}d: stop stall detection", slotId_);
108    stallDetectionEnabled_ = false;
109    RemoveEvent(CellularDataEventCode::MSG_STALL_DETECTION_EVENT_ID);
110}
111
112void DataConnectionMonitor::UpdateFlowInfo()
113{
114    if (stallDetectionTrafficManager_ == nullptr) {
115        TELEPHONY_LOGE("Slot%{public}d: stallDetectionTrafficManager_ is null", slotId_);
116        return;
117    }
118    int64_t previousSentPackets = 0;
119    int64_t previousRecvPackets = 0;
120    int64_t currentSentPackets = 0;
121    int64_t currentRecvPackets = 0;
122    stallDetectionTrafficManager_->GetPacketData(previousSentPackets, previousRecvPackets);
123    stallDetectionTrafficManager_->UpdatePacketData();
124    stallDetectionTrafficManager_->GetPacketData(currentSentPackets, currentRecvPackets);
125    int64_t sentPackets = currentSentPackets - previousSentPackets;
126    int64_t recvPackets = currentRecvPackets - previousRecvPackets;
127    if (sentPackets > 0 && recvPackets == 0) {
128        noRecvPackets_ += sentPackets;
129    } else if ((sentPackets > 0 && recvPackets > 0) || (sentPackets == 0 && recvPackets > 0)) {
130        noRecvPackets_ = 0;
131        dataRecoveryState_ = RecoveryState::STATE_REQUEST_CONTEXT_LIST;
132    } else {
133        TELEPHONY_LOGD("Slot%{public}d: Update Flow Info nothing to do", slotId_);
134    }
135}
136
137void DataConnectionMonitor::HandleRecovery()
138{
139    if (callState_ != static_cast<int32_t>(TelCallStatus::CALL_STATUS_IDLE) &&
140        callState_ != static_cast<int32_t>(TelCallStatus::CALL_STATUS_DISCONNECTED)) {
141        TELEPHONY_LOGI("Slot%{public}d: Stop recovery while call is busy", slotId_);
142        dataRecoveryState_ = RecoveryState::STATE_REQUEST_CONTEXT_LIST;
143        return;
144    }
145    switch (dataRecoveryState_) {
146        case RecoveryState::STATE_REQUEST_CONTEXT_LIST: {
147            TELEPHONY_LOGI("Slot%{public}d: Handle Recovery: get data call list", slotId_);
148            dataRecoveryState_ = RecoveryState::STATE_CLEANUP_CONNECTIONS;
149            GetPdpContextList();
150            CellularDataHiSysEvent::WriteDataDeactiveBehaviorEvent(slotId_, DataDisconnectCause::ON_THE_NETWORK_SIDE);
151            break;
152        }
153        case RecoveryState::STATE_CLEANUP_CONNECTIONS: {
154            TELEPHONY_LOGI("Slot%{public}d: Handle Recovery: cleanup connections", slotId_);
155            dataRecoveryState_ = RecoveryState::STATE_REREGISTER_NETWORK;
156            int32_t ret = DelayedRefSingleton<CellularDataService>::GetInstance().ClearAllConnections(
157                slotId_, DisConnectionReason::REASON_RETRY_CONNECTION);
158            if (ret != static_cast<int32_t>(RequestNetCode::REQUEST_SUCCESS)) {
159                TELEPHONY_LOGE("Slot%{public}d: Handle Recovery: cleanup connections failed", slotId_);
160            }
161            break;
162        }
163        case RecoveryState::STATE_REREGISTER_NETWORK: {
164            TELEPHONY_LOGI("Slot%{public}d: Handle Recovery: re-register network", slotId_);
165            dataRecoveryState_ = RecoveryState::STATE_RADIO_STATUS_RESTART;
166            GetPreferredNetworkPara();
167            break;
168        }
169        case RecoveryState::STATE_RADIO_STATUS_RESTART: {
170            TELEPHONY_LOGI("Slot%{public}d: Handle Recovery: radio restart", slotId_);
171            dataRecoveryState_ = RecoveryState::STATE_REQUEST_CONTEXT_LIST;
172            int32_t ret = DelayedRefSingleton<CellularDataService>::GetInstance().ClearAllConnections(
173                slotId_, DisConnectionReason::REASON_RETRY_CONNECTION);
174            if (ret != static_cast<int32_t>(RequestNetCode::REQUEST_SUCCESS)) {
175                TELEPHONY_LOGE("Slot%{public}d: Handle Recovery: radio restart cleanup connections failed", slotId_);
176            }
177            SetRadioState(CORE_SERVICE_POWER_OFF, RadioEvent::RADIO_OFF);
178            break;
179        }
180        default: {
181            TELEPHONY_LOGE("Slot%{public}d: Handle Recovery is falsie", slotId_);
182            break;
183        }
184    }
185}
186
187void DataConnectionMonitor::BeginNetStatistics()
188{
189    updateNetStat_ = true;
190    UpdateNetTrafficState();
191}
192
193void DataConnectionMonitor::UpdateCallState(int32_t state)
194{
195    callState_ = state;
196}
197
198void DataConnectionMonitor::EndNetStatistics()
199{
200    RemoveEvent(CellularDataEventCode::MSG_RUN_MONITOR_TASK);
201    updateNetStat_ = false;
202    if (dataFlowType_ != CellDataFlowType::DATA_FLOW_TYPE_NONE) {
203        dataFlowType_ = CellDataFlowType::DATA_FLOW_TYPE_NONE;
204        StateNotification::GetInstance().OnUpDataFlowtype(slotId_, dataFlowType_);
205    }
206}
207
208void DataConnectionMonitor::UpdateNetTrafficState()
209{
210    if (!HasInnerEvent(CellularDataEventCode::MSG_RUN_MONITOR_TASK) && updateNetStat_) {
211        UpdateDataFlowType();
212        AppExecFwk::InnerEvent::Pointer event =
213            AppExecFwk::InnerEvent::Get(CellularDataEventCode::MSG_RUN_MONITOR_TASK);
214        SendEvent(event, DEFAULT_NET_STATISTICS_PERIOD);
215    }
216}
217
218void DataConnectionMonitor::GetPdpContextList()
219{
220    CoreManagerInner::GetInstance().GetPdpContextList(slotId_,
221        RadioEvent::RADIO_DATA_CALL_LIST_CHANGED, shared_from_this());
222}
223
224void DataConnectionMonitor::SetRadioState(const int32_t &radioState, const int32_t &eventCode)
225{
226    CoreManagerInner::GetInstance().SetRadioState(slotId_, eventCode, radioState, 0, shared_from_this());
227}
228
229void DataConnectionMonitor::GetPreferredNetworkPara()
230{
231    CoreManagerInner::GetInstance().GetPreferredNetworkPara(slotId_,
232        RadioEvent::RADIO_GET_PREFERRED_NETWORK_MODE, shared_from_this());
233}
234
235void DataConnectionMonitor::SetPreferredNetworkPara(const AppExecFwk::InnerEvent::Pointer &event)
236{
237    std::shared_ptr<PreferredNetworkTypeInfo> preferredNetworkInfo = event->GetSharedObject<PreferredNetworkTypeInfo>();
238    if (preferredNetworkInfo == nullptr) {
239        TELEPHONY_LOGE("preferredNetworkInfo is null");
240        return;
241    }
242    int32_t networkType = preferredNetworkInfo->preferredNetworkType;
243    CoreManagerInner::GetInstance().SetPreferredNetworkPara(slotId_,
244        RadioEvent::RADIO_SET_PREFERRED_NETWORK_MODE, networkType, shared_from_this());
245}
246
247RecoveryState DataConnectionMonitor::GetDataRecoveryState()
248{
249    return dataRecoveryState_;
250}
251
252void DataConnectionMonitor::UpdateDataFlowType()
253{
254    if (trafficManager_ == nullptr) {
255        TELEPHONY_LOGE("Slot%{public}d: trafficManager is null", slotId_);
256        return;
257    }
258    int64_t previousSentPackets = 0;
259    int64_t previousRecvPackets = 0;
260    int64_t currentSentPackets = 0;
261    int64_t currentRecvPackets = 0;
262    trafficManager_->GetPacketData(previousSentPackets, previousRecvPackets);
263    trafficManager_->UpdatePacketData();
264    trafficManager_->GetPacketData(currentSentPackets, currentRecvPackets);
265    int64_t sentPackets = currentSentPackets - previousSentPackets;
266    int64_t recvPackets = currentRecvPackets - previousRecvPackets;
267    CellDataFlowType previousDataFlowType = dataFlowType_;
268    if (previousSentPackets != 0 || previousRecvPackets != 0) {
269        if (sentPackets > 0 && recvPackets == 0) {
270            dataFlowType_ = CellDataFlowType::DATA_FLOW_TYPE_UP;
271        } else if (sentPackets == 0 && recvPackets > 0) {
272            dataFlowType_ = CellDataFlowType::DATA_FLOW_TYPE_DOWN;
273        } else if (sentPackets > 0 && recvPackets > 0) {
274            dataFlowType_ = CellDataFlowType::DATA_FLOW_TYPE_UP_DOWN;
275        } else {
276            dataFlowType_ = CellDataFlowType::DATA_FLOW_TYPE_NONE;
277        }
278    }
279    if (previousDataFlowType != dataFlowType_) {
280        StateNotification::GetInstance().OnUpDataFlowtype(slotId_, dataFlowType_);
281    }
282}
283
284CellDataFlowType DataConnectionMonitor::GetDataFlowType()
285{
286    return dataFlowType_;
287}
288
289void DataConnectionMonitor::SetDataFlowType(CellDataFlowType dataFlowType)
290{
291    if (dataFlowType_ != dataFlowType) {
292        dataFlowType_ = dataFlowType;
293        StateNotification::GetInstance().OnUpDataFlowtype(slotId_, dataFlowType_);
294    }
295}
296
297void DataConnectionMonitor::IsNeedDoRecovery(bool needDoRecovery)
298{
299    if (needDoRecovery) {
300        HandleRecovery();
301    } else {
302        dataRecoveryState_ = RecoveryState::STATE_REQUEST_CONTEXT_LIST;
303    }
304    int32_t stallDetectionPeriod = GetStallDetectionPeriod();
305    TELEPHONY_LOGI("stallDetectionPeriod = %{public}d", stallDetectionPeriod);
306    if (!HasInnerEvent(CellularDataEventCode::MSG_STALL_DETECTION_EVENT_ID) && stallDetectionEnabled_) {
307        AppExecFwk::InnerEvent::Pointer event =
308            AppExecFwk::InnerEvent::Get(CellularDataEventCode::MSG_STALL_DETECTION_EVENT_ID);
309        SendEvent(event, stallDetectionPeriod, Priority::LOW);
310    }
311}
312
313void DataConnectionMonitor::ProcessEvent(const AppExecFwk::InnerEvent::Pointer &event)
314{
315    if (event == nullptr) {
316        TELEPHONY_LOGE("Slot%{public}d: event is null", slotId_);
317        return;
318    }
319    uint32_t eventID = event->GetInnerEventId();
320    switch (eventID) {
321        case CellularDataEventCode::MSG_RUN_MONITOR_TASK: {
322            UpdateNetTrafficState();
323            break;
324        }
325        case CellularDataEventCode::MSG_STALL_DETECTION_EVENT_ID:
326            OnStallDetectionTimer();
327            break;
328        case RadioEvent::RADIO_DATA_CALL_LIST_CHANGED:
329            TELEPHONY_LOGI("Slot%{public}d: radio call list changed complete", slotId_);
330            break;
331        case RadioEvent::RADIO_GET_PREFERRED_NETWORK_MODE:
332            SetPreferredNetworkPara(event);
333            break;
334        case RadioEvent::RADIO_SET_PREFERRED_NETWORK_MODE:
335            TELEPHONY_LOGI("Slot%{public}d: set preferred network mode complete", slotId_);
336            break;
337        case RadioEvent::RADIO_OFF:
338            SetRadioState(CORE_SERVICE_POWER_ON, RadioEvent::RADIO_ON);
339            break;
340        case RadioEvent::RADIO_ON:
341            TELEPHONY_LOGI("Slot%{public}d: set radio state on complete", slotId_);
342            break;
343        default:
344            TELEPHONY_LOGI("Slot%{public}d: connection monitor ProcessEvent code = %{public}u", slotId_, eventID);
345            break;
346    }
347}
348} // namespace Telephony
349} // namespace OHOS
350