* Copyright (C) 2021 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "core_manager_inner.h"
#include "cellular_data_hisysevent.h"
#include "cellular_data_service.h"
#include "data_service_ext_wrapper.h"
#include "telephony_ext_wrapper.h"
namespace OHOS {
namespace Telephony {
DataConnectionMonitor::DataConnectionMonitor(int32_t slotId) : TelEventHandler("DataConnectionMonitor"), slotId_(slotId)
{
trafficManager_ = std::make_unique<TrafficManagement>(slotId);
stallDetectionTrafficManager_ = std::make_unique<TrafficManagement>(slotId);
if (trafficManager_ == nullptr || stallDetectionTrafficManager_ == nullptr) {
TELEPHONY_LOGE("TrafficManager or stallDetectionTrafficManager init failed");
}
}
void DataConnectionMonitor::HandleScreenStateChanged(bool isScreenOn)
{
if (isScreenOn_ == isScreenOn) {
return;
}
isScreenOn_ = isScreenOn;
const int32_t defSlotId = CoreManagerInner::GetInstance().GetDefaultCellularDataSlotId();
if (slotId_ != defSlotId && !IsVsimEnabled()) {
return;
}
StopStallDetectionTimer();
StartStallDetectionTimer();
}
bool DataConnectionMonitor::IsVsimEnabled()
{
#ifdef OHOS_BUILD_ENABLE_TELEPHONY_EXT
if (TELEPHONY_EXT_WRAPPER.getVSimSlotId_ && TELEPHONY_EXT_WRAPPER.isVSimEnabled_) {
int vSimSlotId = INVALID_SLOT_ID;
TELEPHONY_EXT_WRAPPER.getVSimSlotId_(vSimSlotId);
if (vSimSlotId == slotId_ && TELEPHONY_EXT_WRAPPER.isVSimEnabled_()) {
return true;
}
}
#endif
return false;
}
bool DataConnectionMonitor::IsAggressiveRecovery()
{
return (dataRecoveryState_ == RecoveryState::STATE_CLEANUP_CONNECTIONS) ||
(dataRecoveryState_ == RecoveryState::STATE_REREGISTER_NETWORK) ||
(dataRecoveryState_ == RecoveryState::STATE_RADIO_STATUS_RESTART);
}
int32_t DataConnectionMonitor::GetStallDetectionPeriod()
{
if (isScreenOn_ || IsAggressiveRecovery()) {
return DATA_STALL_ALARM_AGGRESSIVE_DELAY_IN_MS_DEFAULT;
}
return DATA_STALL_ALARM_NON_AGGRESSIVE_DELAY_IN_MS_DEFAULT;
}
void DataConnectionMonitor::StartStallDetectionTimer()
{
TELEPHONY_LOGD("Slot%{public}d: start stall detection", slotId_);
stallDetectionEnabled_ = true;
int32_t stallDetectionPeriod = GetStallDetectionPeriod();
TELEPHONY_LOGD("stallDetectionPeriod = %{public}d", stallDetectionPeriod);
if (!HasInnerEvent(CellularDataEventCode::MSG_STALL_DETECTION_EVENT_ID)) {
AppExecFwk::InnerEvent::Pointer event =
AppExecFwk::InnerEvent::Get(CellularDataEventCode::MSG_STALL_DETECTION_EVENT_ID);
SendEvent(event, stallDetectionPeriod, Priority::LOW);
}
}
__attribute__((no_sanitize("cfi"))) void DataConnectionMonitor::OnStallDetectionTimer()
{
TELEPHONY_LOGD("Slot%{public}d: on stall detection", slotId_);
#ifdef OHOS_BUILD_ENABLE_DATA_SERVICE_EXT
if (DATA_SERVICE_EXT_WRAPPER.requestTcpAndDnsPackets_) {
DATA_SERVICE_EXT_WRAPPER.requestTcpAndDnsPackets_();
return;
}
#endif
UpdateFlowInfo();
int32_t dataState = static_cast<int32_t>(DataConnectState::DATA_STATE_UNKNOWN);
DelayedRefSingleton<CellularDataService>::GetInstance().GetCellularDataState(dataState);
if (noRecvPackets_ > RECOVERY_TRIGGER_PACKET ||
(dataState != static_cast<int32_t>(DataConnectionStatus::DATA_STATE_CONNECTED) &&
dataRecoveryState_ == RecoveryState::STATE_RADIO_STATUS_RESTART)) {
HandleRecovery();
noRecvPackets_ = 0;
}
int32_t stallDetectionPeriod = GetStallDetectionPeriod();
TELEPHONY_LOGD("stallDetectionPeriod = %{public}d", stallDetectionPeriod);
if (!HasInnerEvent(CellularDataEventCode::MSG_STALL_DETECTION_EVENT_ID) && stallDetectionEnabled_) {
AppExecFwk::InnerEvent::Pointer event =
AppExecFwk::InnerEvent::Get(CellularDataEventCode::MSG_STALL_DETECTION_EVENT_ID);
SendEvent(event, stallDetectionPeriod, Priority::LOW);
}
}
void DataConnectionMonitor::StopStallDetectionTimer()
{
TELEPHONY_LOGD("Slot%{public}d: stop stall detection", slotId_);
stallDetectionEnabled_ = false;
RemoveEvent(CellularDataEventCode::MSG_STALL_DETECTION_EVENT_ID);
}
void DataConnectionMonitor::UpdateFlowInfo()
{
if (stallDetectionTrafficManager_ == nullptr) {
TELEPHONY_LOGE("Slot%{public}d: stallDetectionTrafficManager_ is null", slotId_);
return;
}
int64_t previousSentPackets = 0;
int64_t previousRecvPackets = 0;
int64_t currentSentPackets = 0;
int64_t currentRecvPackets = 0;
stallDetectionTrafficManager_->GetPacketData(previousSentPackets, previousRecvPackets);
stallDetectionTrafficManager_->UpdatePacketData();
stallDetectionTrafficManager_->GetPacketData(currentSentPackets, currentRecvPackets);
int64_t sentPackets = currentSentPackets - previousSentPackets;
int64_t recvPackets = currentRecvPackets - previousRecvPackets;
if (sentPackets > 0 && recvPackets == 0) {
noRecvPackets_ += sentPackets;
} else if ((sentPackets > 0 && recvPackets > 0) || (sentPackets == 0 && recvPackets > 0)) {
noRecvPackets_ = 0;
dataRecoveryState_ = RecoveryState::STATE_REQUEST_CONTEXT_LIST;
} else {
TELEPHONY_LOGD("Slot%{public}d: Update Flow Info nothing to do", slotId_);
}
}
void DataConnectionMonitor::HandleRecovery()
{
if (callState_ != static_cast<int32_t>(TelCallStatus::CALL_STATUS_IDLE) &&
callState_ != static_cast<int32_t>(TelCallStatus::CALL_STATUS_DISCONNECTED)) {
TELEPHONY_LOGI("Slot%{public}d: Stop recovery while call is busy", slotId_);
dataRecoveryState_ = RecoveryState::STATE_REQUEST_CONTEXT_LIST;
return;
}
switch (dataRecoveryState_) {
case RecoveryState::STATE_REQUEST_CONTEXT_LIST: {
TELEPHONY_LOGI("Slot%{public}d: Handle Recovery: get data call list", slotId_);
dataRecoveryState_ = RecoveryState::STATE_CLEANUP_CONNECTIONS;
GetPdpContextList();
CellularDataHiSysEvent::WriteDataDeactiveBehaviorEvent(slotId_, DataDisconnectCause::ON_THE_NETWORK_SIDE);
break;
}
case RecoveryState::STATE_CLEANUP_CONNECTIONS: {
TELEPHONY_LOGI("Slot%{public}d: Handle Recovery: cleanup connections", slotId_);
dataRecoveryState_ = RecoveryState::STATE_REREGISTER_NETWORK;
int32_t ret = DelayedRefSingleton<CellularDataService>::GetInstance().ClearAllConnections(
slotId_, (int32_t) DisConnectionReason::REASON_RETRY_CONNECTION);
if (ret != static_cast<int32_t>(RequestNetCode::REQUEST_SUCCESS)) {
TELEPHONY_LOGE("Slot%{public}d: Handle Recovery: cleanup connections failed", slotId_);
}
break;
}
case RecoveryState::STATE_REREGISTER_NETWORK: {
TELEPHONY_LOGI("Slot%{public}d: Handle Recovery: re-register network", slotId_);
dataRecoveryState_ = RecoveryState::STATE_RADIO_STATUS_RESTART;
ReregisterNetwork();
break;
}
case RecoveryState::STATE_RADIO_STATUS_RESTART: {
TELEPHONY_LOGI("Slot%{public}d: Handle Recovery: radio restart", slotId_);
dataRecoveryState_ = RecoveryState::STATE_REQUEST_CONTEXT_LIST;
int32_t ret = DelayedRefSingleton<CellularDataService>::GetInstance().ClearAllConnections(
slotId_, (int32_t)DisConnectionReason::REASON_RETRY_CONNECTION);
if (ret != static_cast<int32_t>(RequestNetCode::REQUEST_SUCCESS)) {
TELEPHONY_LOGE("Slot%{public}d: Handle Recovery: radio restart cleanup connections failed", slotId_);
}
SetRadioState(CORE_SERVICE_POWER_OFF, RadioEvent::RADIO_OFF);
break;
}
default: {
TELEPHONY_LOGE("Slot%{public}d: Handle Recovery is falsie", slotId_);
break;
}
}
}
void DataConnectionMonitor::BeginNetStatistics()
{
updateNetStat_ = true;
UpdateNetTrafficState();
}
void DataConnectionMonitor::UpdateCallState(int32_t state)
{
callState_ = state;
}
void DataConnectionMonitor::EndNetStatistics()
{
RemoveEvent(CellularDataEventCode::MSG_RUN_MONITOR_TASK);
updateNetStat_ = false;
if (dataFlowType_ != CellDataFlowType::DATA_FLOW_TYPE_NONE) {
dataFlowType_ = CellDataFlowType::DATA_FLOW_TYPE_NONE;
StateNotification::GetInstance().OnUpDataFlowtype(slotId_, dataFlowType_);
}
}
void DataConnectionMonitor::UpdateNetTrafficState()
{
if (!HasInnerEvent(CellularDataEventCode::MSG_RUN_MONITOR_TASK) && updateNetStat_) {
UpdateDataFlowType();
AppExecFwk::InnerEvent::Pointer event =
AppExecFwk::InnerEvent::Get(CellularDataEventCode::MSG_RUN_MONITOR_TASK);
SendEvent(event, DEFAULT_NET_STATISTICS_PERIOD);
}
}
void DataConnectionMonitor::GetPdpContextList()
{
CoreManagerInner::GetInstance().GetPdpContextList(slotId_,
RadioEvent::RADIO_DATA_CALL_LIST_CHANGED, shared_from_this());
}
void DataConnectionMonitor::SetRadioState(const int32_t &radioState, const int32_t &eventCode)
{
CoreManagerInner::GetInstance().SetRadioState(slotId_, eventCode, radioState, 0, shared_from_this());
}
void DataConnectionMonitor::ReregisterNetwork()
{
bool isProcess = false;
#ifdef OHOS_BUILD_ENABLE_TELEPHONY_EXT
if (TELEPHONY_EXT_WRAPPER.reRegisterNetwork_) {
TELEPHONY_EXT_WRAPPER.reRegisterNetwork_(slotId_, isProcess);
}
#endif
TELEPHONY_LOGI("ReregisterNetwork isProcess:%{public}d", isProcess);
if (isProcess) {
return;
}
CoreManagerInner::GetInstance().GetPreferredNetworkPara(slotId_,
RadioEvent::RADIO_GET_PREFERRED_NETWORK_MODE, shared_from_this());
}
void DataConnectionMonitor::SetPreferredNetworkPara(const AppExecFwk::InnerEvent::Pointer &event)
{
std::shared_ptr<PreferredNetworkTypeInfo> preferredNetworkInfo = event->GetSharedObject<PreferredNetworkTypeInfo>();
if (preferredNetworkInfo == nullptr) {
TELEPHONY_LOGE("preferredNetworkInfo is null");
return;
}
int32_t networkType = preferredNetworkInfo->preferredNetworkType;
CoreManagerInner::GetInstance().SetPreferredNetworkPara(slotId_,
RadioEvent::RADIO_SET_PREFERRED_NETWORK_MODE, networkType, shared_from_this());
}
RecoveryState DataConnectionMonitor::GetDataRecoveryState()
{
return dataRecoveryState_;
}
void DataConnectionMonitor::UpdateDataFlowType()
{
if (trafficManager_ == nullptr) {
TELEPHONY_LOGE("Slot%{public}d: trafficManager is null", slotId_);
return;
}
int64_t previousSentPackets = 0;
int64_t previousRecvPackets = 0;
int64_t currentSentPackets = 0;
int64_t currentRecvPackets = 0;
trafficManager_->GetPacketData(previousSentPackets, previousRecvPackets);
trafficManager_->UpdatePacketData();
trafficManager_->GetPacketData(currentSentPackets, currentRecvPackets);
int64_t sentPackets = currentSentPackets - previousSentPackets;
int64_t recvPackets = currentRecvPackets - previousRecvPackets;
CellDataFlowType previousDataFlowType = dataFlowType_;
if (previousSentPackets != 0 || previousRecvPackets != 0) {
if (sentPackets > 0 && recvPackets == 0) {
dataFlowType_ = CellDataFlowType::DATA_FLOW_TYPE_UP;
} else if (sentPackets == 0 && recvPackets > 0) {
dataFlowType_ = CellDataFlowType::DATA_FLOW_TYPE_DOWN;
} else if (sentPackets > 0 && recvPackets > 0) {
dataFlowType_ = CellDataFlowType::DATA_FLOW_TYPE_UP_DOWN;
} else {
dataFlowType_ = CellDataFlowType::DATA_FLOW_TYPE_NONE;
}
}
if (previousDataFlowType != dataFlowType_) {
StateNotification::GetInstance().OnUpDataFlowtype(slotId_, dataFlowType_);
}
}
CellDataFlowType DataConnectionMonitor::GetDataFlowType()
{
return dataFlowType_;
}
void DataConnectionMonitor::SetDataFlowType(CellDataFlowType dataFlowType)
{
if (dataFlowType_ != dataFlowType) {
dataFlowType_ = dataFlowType;
StateNotification::GetInstance().OnUpDataFlowtype(slotId_, dataFlowType_);
}
}
void DataConnectionMonitor::IsNeedDoRecovery(bool needDoRecovery)
{
if (needDoRecovery) {
HandleRecovery();
} else {
dataRecoveryState_ = RecoveryState::STATE_REQUEST_CONTEXT_LIST;
}
int32_t stallDetectionPeriod = GetStallDetectionPeriod();
TELEPHONY_LOGD("stallDetectionPeriod = %{public}d", stallDetectionPeriod);
if (!HasInnerEvent(CellularDataEventCode::MSG_STALL_DETECTION_EVENT_ID) && stallDetectionEnabled_) {
AppExecFwk::InnerEvent::Pointer event =
AppExecFwk::InnerEvent::Get(CellularDataEventCode::MSG_STALL_DETECTION_EVENT_ID);
SendEvent(event, stallDetectionPeriod, Priority::LOW);
}
}
void DataConnectionMonitor::ProcessEvent(const AppExecFwk::InnerEvent::Pointer &event)
{
if (event == nullptr) {
TELEPHONY_LOGE("Slot%{public}d: event is null", slotId_);
return;
}
uint32_t eventID = event->GetInnerEventId();
switch (eventID) {
case CellularDataEventCode::MSG_RUN_MONITOR_TASK: {
UpdateNetTrafficState();
break;
}
case CellularDataEventCode::MSG_STALL_DETECTION_EVENT_ID:
OnStallDetectionTimer();
break;
case RadioEvent::RADIO_DATA_CALL_LIST_CHANGED:
TELEPHONY_LOGI("Slot%{public}d: radio call list changed complete", slotId_);
break;
case RadioEvent::RADIO_GET_PREFERRED_NETWORK_MODE:
SetPreferredNetworkPara(event);
break;
case RadioEvent::RADIO_SET_PREFERRED_NETWORK_MODE:
TELEPHONY_LOGI("Slot%{public}d: set preferred network mode complete", slotId_);
break;
case RadioEvent::RADIO_OFF:
SetRadioState(CORE_SERVICE_POWER_ON, RadioEvent::RADIO_ON);
break;
case RadioEvent::RADIO_ON:
TELEPHONY_LOGI("Slot%{public}d: set radio state on complete", slotId_);
break;
default:
TELEPHONY_LOGI("Slot%{public}d: connection monitor ProcessEvent code = %{public}u", slotId_, eventID);
break;
}
}
}
}