/* * Copyright (C) 2021-2023 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 "gsm_sms_cb_handler.h" #include "common_event_support.h" #include "core_manager_inner.h" #include "radio_event.h" #include "securec.h" #include "singleton.h" #include "sms_hisysevent.h" #include "string_utils.h" #include "telephony_log_wrapper.h" #include "telephony_permission.h" namespace OHOS { namespace Telephony { using namespace OHOS::EventFwk; GsmSmsCbHandler::GsmSmsCbHandler(const std::shared_ptr &runner, int32_t slotId) : AppExecFwk::EventHandler(runner), slotId_(slotId) { TELEPHONY_LOGI("GsmSmsCbHandler Create slotId (%{public}d)", slotId_); } void GsmSmsCbHandler::Init() { cbMsgList_.clear(); CoreManagerInner::GetInstance().RegisterCoreNotify( slotId_, shared_from_this(), RadioEvent::RADIO_CELL_BROADCAST, nullptr); TELEPHONY_LOGI("GsmSmsCbHandler::RegisterHandler::slotId= %{public}d", slotId_); } void GsmSmsCbHandler::UnRegisterHandler() { CoreManagerInner::GetInstance().UnRegisterCoreNotify(slotId_, shared_from_this(), RadioEvent::RADIO_CELL_BROADCAST); } bool GsmSmsCbHandler::CheckCbActive(const std::shared_ptr &cbMessage) { if (cbMessage == nullptr) { TELEPHONY_LOGE("CbMessage is null!"); return false; } return true; } uint8_t GsmSmsCbHandler::CheckCbMessage(const std::shared_ptr &cbMessage) { uint8_t currPageCnt = 0; bool bFind = false; if (cbMessage == nullptr) { TELEPHONY_LOGE("CheckCbMessage cbMessage nullptr err."); return currPageCnt; } std::shared_ptr cbHeader = cbMessage->GetCbHeader(); if (cbHeader == nullptr || cbHeader->totalPages == 0) { TELEPHONY_LOGE("CheckCbMessage GetCbHeader err."); return currPageCnt; } for (std::size_t i = 0; i < cbMsgList_.size(); i++) { SmsCbInfo &cbInfo = cbMsgList_[i]; if (*cbInfo.header.get() == *cbHeader.get()) { int updateNum = cbHeader->serialNum.updateNum - cbInfo.header->serialNum.updateNum; if (updateNum != 0) { break; } if (cbInfo.cbMsgs.count(cbHeader->page)) { currPageCnt = 0x01; return currPageCnt; } cbInfo.cbMsgs.insert(std::make_pair(cbHeader->page, cbMessage)); currPageCnt = cbInfo.cbMsgs.size(); bFind = true; break; } } if (bFind == false || cbHeader->totalPages == 0x01) { AddCbMessageToList(cbMessage); currPageCnt = 0x01; } return currPageCnt; } std::unique_ptr GsmSmsCbHandler::FindCbMessage(const std::shared_ptr &cbMessage) { std::unique_ptr cbInfo = nullptr; if (cbMessage == nullptr) { TELEPHONY_LOGE("FindCbMessage cbMessage nullptr err."); return cbInfo; } std::shared_ptr cbHeader = cbMessage->GetCbHeader(); if (cbHeader == nullptr) { TELEPHONY_LOGE("FindCbMessage header err."); return cbInfo; } for (std::size_t i = 0; i < cbMsgList_.size(); i++) { SmsCbInfo &info = cbMsgList_[i]; if (*info.header.get() == *cbHeader.get()) { cbInfo = std::make_unique(info.header, info.cbMsgs); if (cbInfo == nullptr) { TELEPHONY_LOGE("Make SmsCbInfo err."); return cbInfo; } } } return cbInfo; } bool GsmSmsCbHandler::AddCbMessageToList(const std::shared_ptr &cbMessage) { if (cbMessage == nullptr) { TELEPHONY_LOGE("AddCbMessageToList cbMessage nullptr err."); return false; } std::shared_ptr cbHeader = cbMessage->GetCbHeader(); if (cbHeader == nullptr) { TELEPHONY_LOGE("AddCbMessageToList header err."); return false; } std::unique_ptr cbInfo = FindCbMessage(cbMessage); if (cbInfo == nullptr) { SmsCbInfo info; info.header = cbHeader; info.cbMsgs.insert(std::make_pair(cbHeader->page, cbMessage)); InitLocation(info); cbMsgList_.push_back(info); return true; } return false; } bool GsmSmsCbHandler::InitLocation(SmsCbInfo &info) { const uint8_t cellWideImmediate = 0; const uint8_t plmnWide = 1; const uint8_t LaWide = 2; const uint8_t cellWide = 3; const int32_t defaultValue = -1; info.plmn_ = CoreManagerInner::GetInstance().GetOperatorNumeric(slotId_); sptr location = CoreManagerInner::GetInstance().GetCellLocation(slotId_); if (location == nullptr) { TELEPHONY_LOGE("location is nullptr."); return false; } if (location->GetCellLocationType() != CellLocation::CellType::CELL_TYPE_GSM) { TELEPHONY_LOGE("location type isn't GSM."); return false; } sptr gsmLocation = sptr(static_cast(location.GetRefPtr())); info.lac_ = gsmLocation->GetLac(); info.cid_ = gsmLocation->GetCellId(); TELEPHONY_LOGI("plmn = %{private}s lac = %{private}s cid = %{private}s", StringUtils::ToUtf8(info.plmn_).c_str(), std::to_string(info.lac_).c_str(), std::to_string(info.cid_).c_str()); switch (info.header->serialNum.geoScope) { case LaWide: info.cid_ = defaultValue; break; case cellWide: case cellWideImmediate: break; case plmnWide: default: info.cid_ = defaultValue; info.lac_ = defaultValue; break; } plmn_ = info.plmn_; cid_ = info.cid_; lac_ = info.lac_; return true; } bool GsmSmsCbHandler::RemoveCbMessageFromList(const std::shared_ptr &cbMessage) { bool result = false; if (cbMessage == nullptr) { TELEPHONY_LOGE("RemoveCbMessageFromList cbMessage nullptr err."); return false; } std::shared_ptr header = cbMessage->GetCbHeader(); if (header == nullptr) { TELEPHONY_LOGE("RemoveCbMessageFromList header err."); return false; } auto it = cbMsgList_.begin(); while (it != cbMsgList_.end()) { SmsCbInfo &info = *it; if (*info.header.get() == *header.get() || !info.MatchLocation(plmn_, lac_, cid_)) { it = cbMsgList_.erase(it); result = true; } else { ++it; } } return result; } void GsmSmsCbHandler::HandleCbMessage(std::shared_ptr &message) { if (message == nullptr) { TELEPHONY_LOGE("GsmSmsCbHandler HandleCbMessage message == nullptr"); return; } std::string pdu(message->pdu); std::shared_ptr cbMessage = GsmCbCodec::CreateCbMessage(pdu); if (cbMessage == nullptr) { TELEPHONY_LOGE("create Sms CbMessage fail, pdu %{private}s", pdu.c_str()); SmsHiSysEvent::WriteSmsReceiveFaultEvent(slotId_, SmsMmsMessageType::CELL_BROAD_CAST, SmsMmsErrorCode::SMS_ERROR_CELL_BROADCAST_PUD_ANALYSIS_FAIL, "publish cell broadcast event fail"); return; } std::shared_ptr header = cbMessage->GetCbHeader(); if (header == nullptr) { TELEPHONY_LOGE("HandleCbMessage header is null."); return; } if (!CheckCbActive(cbMessage)) { TELEPHONY_LOGE("The Cell Broadcast msg is not active"); return; } uint8_t pageCnt = CheckCbMessage(cbMessage); if (header->totalPages == pageCnt) { SendCbMessageBroadcast(cbMessage); RemoveCbMessageFromList(cbMessage); } } bool GsmSmsCbHandler::SendCbMessageBroadcast(const std::shared_ptr &cbMessage) { if (cbMessage == nullptr) { TELEPHONY_LOGE("SendCbMessageBroadcast cbMessage nullptr err."); return false; } EventFwk::Want want; EventFwk::CommonEventData data; if (!SetWantData(want, cbMessage)) { TELEPHONY_LOGE("SendCbMessageBroadcast SetWantData fail."); return false; } data.SetWant(want); EventFwk::CommonEventPublishInfo publishInfo; publishInfo.SetOrdered(true); std::vector gsmCbPermissions; gsmCbPermissions.emplace_back(Permission::RECEIVE_MESSAGES); publishInfo.SetSubscriberPermissions(gsmCbPermissions); bool publishResult = EventFwk::CommonEventManager::PublishCommonEvent(data, publishInfo, nullptr); if (!publishResult) { TELEPHONY_LOGE("SendBroadcast PublishBroadcastEvent result fail"); SmsHiSysEvent::WriteSmsReceiveFaultEvent(slotId_, SmsMmsMessageType::CELL_BROAD_CAST, SmsMmsErrorCode::SMS_ERROR_PUBLISH_COMMON_EVENT_FAIL, "publish cell broadcast event fail"); return false; } DelayedSingleton::GetInstance()->SetCbBroadcastStartTime(); return true; } void GsmSmsCbHandler::ProcessEvent(const AppExecFwk::InnerEvent::Pointer &event) { if (event == nullptr) { TELEPHONY_LOGE("GsmSmsCbHandler event nullptr error."); return; } uint32_t eventId = 0; eventId = event->GetInnerEventId(); TELEPHONY_LOGI("ProcessEvent eventId = %{public}d", eventId); switch (eventId) { case RadioEvent::RADIO_CELL_BROADCAST: { std::shared_ptr cbMessage = nullptr; cbMessage = event->GetSharedObject(); HandleCbMessage(cbMessage); break; } default: TELEPHONY_LOGE("GsmSmsCbHandler eventId unknown error."); break; } } bool GsmSmsCbHandler::SetWantData(EventFwk::Want &want, const std::shared_ptr &cbMessage) { if (cbMessage == nullptr) { TELEPHONY_LOGE("cbMessage is nullptr."); return false; } SmsCbData::CbData sendData; std::unique_ptr info = FindCbMessage(cbMessage); if (info == nullptr) { TELEPHONY_LOGE("find cb message fail."); return false; } std::string rawMsgBody; for (auto it = info->cbMsgs.begin(); it != info->cbMsgs.end(); it++) { rawMsgBody.append(it->second->GetCbMessageRaw()); } GetCbData(cbMessage, sendData); cbMessage->ConvertToUTF8(rawMsgBody, sendData.msgBody); want.SetParam(SmsCbData::GEO_SCOPE, static_cast(sendData.geoScope)); want.SetParam(SmsCbData::CMAS_RESPONSE, static_cast(sendData.cmasRes)); want.SetParam(SmsCbData::SLOT_ID, static_cast(slotId_)); want.SetParam(SmsCbData::FORMAT, static_cast(sendData.format)); want.SetParam(SmsCbData::CB_MSG_TYPE, static_cast(sendData.msgType)); want.SetParam(SmsCbData::MSG_ID, static_cast(sendData.msgId)); want.SetParam(SmsCbData::SERVICE_CATEGORY, static_cast(sendData.category)); want.SetParam(SmsCbData::LANG_TYPE, static_cast(sendData.langType)); want.SetParam(SmsCbData::PRIORITY, static_cast(sendData.priority)); want.SetParam(SmsCbData::MSG_BODY, sendData.msgBody); want.SetParam(SmsCbData::CMAS_CLASS, static_cast(sendData.cmasClass)); want.SetParam(SmsCbData::CMAS_CATEGORY, static_cast(sendData.cmasCate)); want.SetParam(SmsCbData::SEVERITY, static_cast(sendData.severity)); want.SetParam(SmsCbData::URGENCY, static_cast(sendData.urgency)); want.SetParam(SmsCbData::CERTAINTY, static_cast(sendData.certainty)); want.SetParam(SmsCbData::IS_CMAS_MESSAGE, sendData.isCmas); want.SetParam(SmsCbData::SERIAL_NUM, static_cast(sendData.serial)); want.SetParam(SmsCbData::RECV_TIME, std::to_string(sendData.recvTime)); want.SetParam(SmsCbData::DCS, static_cast(sendData.dcs)); want.SetParam(SmsCbData::IS_ETWS_PRIMARY, sendData.isPrimary); want.SetParam(SmsCbData::IS_ETWS_MESSAGE, sendData.isEtws); want.SetParam(SmsCbData::PLMN, StringUtils::ToUtf8(plmn_)); want.SetParam(SmsCbData::LAC, static_cast(lac_)); want.SetParam(SmsCbData::CID, static_cast(cid_)); want.SetParam(SmsCbData::WARNING_TYPE, static_cast(sendData.warnType)); if (sendData.isPrimary) { want.SetAction(CommonEventSupport::COMMON_EVENT_SMS_EMERGENCY_CB_RECEIVE_COMPLETED); } else { want.SetAction(CommonEventSupport::COMMON_EVENT_SMS_CB_RECEIVE_COMPLETED); } return true; } void GsmSmsCbHandler::GetCbData(const std::shared_ptr &cbMessage, SmsCbData::CbData &sendData) { if (cbMessage == nullptr) { TELEPHONY_LOGE("Get Cb Data error."); return; } cbMessage->GetMsgType(sendData.msgType); cbMessage->GetLangType(sendData.langType); cbMessage->GetDcs(sendData.dcs); cbMessage->GetPriority(sendData.priority); cbMessage->GetCmasMessageClass(sendData.cmasClass); cbMessage->GetCmasResponseType(sendData.cmasRes); cbMessage->GetCmasSeverity(sendData.severity); cbMessage->GetCmasUrgency(sendData.urgency); cbMessage->GetCmasCertainty(sendData.certainty); cbMessage->IsEtwsMessage(sendData.isEtws); cbMessage->GetWarningType(sendData.warnType); cbMessage->IsCmasMessage(sendData.isCmas); cbMessage->GetSerialNum(sendData.serial); cbMessage->GetReceiveTime(sendData.recvTime); cbMessage->GetMessageId(sendData.msgId); cbMessage->GetServiceCategory(sendData.category); cbMessage->GetFormat(sendData.format); cbMessage->IsEtwsPrimary(sendData.isPrimary); cbMessage->GetGeoScope(sendData.geoScope); cbMessage->GetCmasCategory(sendData.cmasCate); } } // namespace Telephony } // namespace OHOS