• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2025 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 "select_network_data_report.h"
17 #include "sta_state_machine.h"
18 #include "wifi_common_util.h"
19 #include "wifi_logger.h"
20 #include "wifi_config_center.h"
21 #include "wifi_settings.h"
22 #include <climits>
23 
24 namespace OHOS {
25 namespace Wifi {
26 
27 DEFINE_WIFILOG_LABEL("SelectNetworkDataReport");
28 
29 namespace WifiDataConstants {
30 
31 constexpr int BEACON_RSSI_LEN = 10;
32 constexpr int CDF_LAST_LEN = 8; // txtime, uldelay 最后长度
33 constexpr int CDF_RAW_LEN = 64; // txtime, uldelay 芯片组件上报到signalpoll的最初长度
34 constexpr int CDF_PROCESS_LEN = 32; // txtime, uldelay int8 转 int16 后的长度
35 constexpr int AI_OFFSET_8 = 8;
36 constexpr int AI_OFFSET_16 = 16;
37 constexpr int AI_OFFSET_24 = 24;
38 constexpr int AI_INDEX_1 = 1;
39 constexpr int AI_INDEX_2 = 2;
40 constexpr int AI_INDEX_3 = 3;
41 constexpr int AI_CW_LEN = 2; // cwmin, cwmax
42 constexpr int CHANNEL_WIDTH_2_4G = 5; // 2.4G频段信道带宽
43 constexpr int CHANNEL_WIDTH_5G = 20; // 5G频段信道带宽
44 constexpr int QOE_INFO_LEN = 149; // signalpoll上报最长长度
45 constexpr int DELAY_TIME = 4 * 60 * 60; // 设置推送时间间隔为DELAY_TIME
46 constexpr int CONN_FAILED_COUNT_THRESHOLD = 3; // 失败上报阈值,防止关联失败重连导致上报
47 constexpr int MAX_PUSH_COUNT = 10; // 10条数据融合为一条上报
48 
49 } // namespace WifiDataConstants
50 
WifiDataReportService(StaStateMachine * staStateMachinePtr,int instId)51 WifiDataReportService::WifiDataReportService(StaStateMachine* staStateMachinePtr, int instId)
52     : StaSMExt(staStateMachinePtr, instId) {}
53 
~WifiDataReportService()54 WifiDataReportService::~WifiDataReportService() {}
55 
56 
InitReportApAllInfo()57 void WifiDataReportService::InitReportApAllInfo()
58 {
59     std::lock_guard<std::mutex> lock(historyMutex_);
60     disConnFlag_ = false;
61     connEventTimepInfo_ = ConnectEventTimeInfo();
62     lastPushTime_.clear();
63     historyData_.clear();
64 }
65 
GetUint32FromExt(const std::vector<uint8_t> & ext,size_t index)66 uint32_t WifiDataReportService::GetUint32FromExt(const std::vector<uint8_t>& ext, size_t index)
67 {
68     if (index + sizeof(uint32_t) - 1 >= ext.size()) {
69         WIFI_LOGE("GetUint32FromExt fail");
70         return 0;
71     }
72     return (static_cast<uint32_t>(ext[index]) |
73             static_cast<uint32_t>(ext[index + WifiDataConstants::AI_INDEX_1]) << WifiDataConstants::AI_OFFSET_8 |
74             static_cast<uint32_t>(ext[index + WifiDataConstants::AI_INDEX_2]) << WifiDataConstants::AI_OFFSET_16 |
75             static_cast<uint32_t>(ext[index + WifiDataConstants::AI_INDEX_3]) << WifiDataConstants::AI_OFFSET_24);
76 }
77 
ConvertUint8ToUint16(const std::vector<uint8_t> & uint8Vec)78 std::vector<uint16_t> WifiDataReportService::ConvertUint8ToUint16(const std::vector<uint8_t>& uint8Vec)
79 {
80     std::vector<uint16_t> uint16Vec;
81     /* 确保输入向量的长度是偶数 */
82     if (uint8Vec.size() % sizeof(uint16_t) != 0) {
83         return uint16Vec;
84     }
85     uint8_t lowByte;
86     uint8_t highByte;
87     uint16_t combined;
88     for (size_t i = 0; i < uint8Vec.size() - 1; i += sizeof(uint16_t)) {
89         /* 获取高位和低位字节 */
90         lowByte = uint8Vec[i];
91         highByte = uint8Vec[i + 1];
92         /* 合并成一个 uint16_t, 高位字节左移8位后与低位字节按位或 */
93         combined = (highByte << WifiDataConstants::AI_OFFSET_8) | lowByte;
94         /* 添加到 uint16_t 向量中 */
95         uint16Vec.push_back(combined);
96     }
97     return uint16Vec;
98 }
99 
SequenceMerge(const std::vector<uint16_t> & sequence)100 std::vector<uint16_t> WifiDataReportService::SequenceMerge(const std::vector<uint16_t>& sequence)
101 {
102     std::vector<uint16_t> mergeSequence(WifiDataConstants::CDF_LAST_LEN, 0);
103     if (sequence.size() != WifiDataConstants::CDF_PROCESS_LEN) {
104         WIFI_LOGE("sequence should have exactly 32 elements.");
105         return mergeSequence;
106     }
107     int index = 0;
108     /* BE */
109     std::vector<uint16_t> cdfBe;
110     cdfBe.insert(cdfBe.end(), sequence.begin() + index, sequence.begin() + index + WifiDataConstants::CDF_LAST_LEN);
111     index = index + WifiDataConstants::CDF_LAST_LEN;
112     /* BK */
113     std::vector<uint16_t> cdfBk;
114     cdfBk.insert(cdfBk.end(), sequence.begin() + index, sequence.begin() + index + WifiDataConstants::CDF_LAST_LEN);
115     index = index + WifiDataConstants::CDF_LAST_LEN;
116     /* VI */
117     std::vector<uint16_t> cdfVi;
118     cdfVi.insert(cdfVi.end(), sequence.begin() + index, sequence.begin() + index + WifiDataConstants::CDF_LAST_LEN);
119     index = index + WifiDataConstants::CDF_LAST_LEN;
120     /* VO */
121     std::vector<uint16_t> cdfVo;
122     cdfVo.insert(cdfVo.end(), sequence.begin() + index, sequence.begin() + index + WifiDataConstants::CDF_LAST_LEN);
123 
124     for (size_t i = 0; i < cdfBe.size(); i++) {
125         mergeSequence[i] = cdfBe[i] + cdfBk[i] + cdfVi[i] + cdfVo[i];
126     }
127     return mergeSequence;
128 }
129 
GetApDeviceInfo(const int & networkId,int instId,WifiDeviceConfig & apDeviceInfo)130 void WifiDataReportService::GetApDeviceInfo(const int& networkId, int instId, WifiDeviceConfig& apDeviceInfo)
131 {
132     if (WifiSettings::GetInstance().GetDeviceConfig(networkId, apDeviceInfo, instId) != 0) {
133         WIFI_LOGE("ReportApConnEventInfo GetDeviceConfig failed!");
134         return;
135     }
136 }
137 
UpdateApConnEventTimepInfo(ConnTimeType timeType)138 void WifiDataReportService::UpdateApConnEventTimepInfo(ConnTimeType timeType)
139 {
140     switch (timeType) {
141         case ConnTimeType::STA_CONN_START:
142             connEventTimepInfo_.timepConnStart = std::time(nullptr);
143             break;
144         case ConnTimeType::STA_DHCP_SUC:
145             connEventTimepInfo_.timepDhcpSuc = std::time(nullptr);
146             connEventTimepInfo_.timeToSucConn =
147                 connEventTimepInfo_.timepDhcpSuc - connEventTimepInfo_.timepConnStart;
148             break;
149         case ConnTimeType::STA_DISCONN_SUC:
150             connEventTimepInfo_.timepDisconnSuc = std::time(nullptr);
151             connEventTimepInfo_.timeToDuraConn =
152                 connEventTimepInfo_.timepDisconnSuc - connEventTimepInfo_.timepDhcpSuc;
153             break;
154         default:
155             break;
156     }
157 }
158 
IsAdjacentChannel(int apFrequency,int targetApFrequency,char wifiBand)159 bool WifiDataReportService::IsAdjacentChannel(int apFrequency, int targetApFrequency, char wifiBand)
160 {
161     int channelWidth = wifiBand == 1 ? WifiDataConstants::CHANNEL_WIDTH_2_4G : WifiDataConstants::CHANNEL_WIDTH_5G;
162 
163     return std::abs(targetApFrequency - apFrequency) <= channelWidth;
164 }
165 
UpdateSameAdjaFreqCount(WifiCrowdsourcedDetailInfo & apDetailInfo,const std::string targetBssid,const int freq,const int band)166 void WifiDataReportService::UpdateSameAdjaFreqCount(WifiCrowdsourcedDetailInfo& apDetailInfo,
167     const std::string targetBssid, const int freq, const int band)
168 {
169     int apSamefreqCount = 0;
170     int apAdjafreqCount = 0;
171 
172     /* 获取扫描结果并判空 */
173     std::vector<WifiScanInfo> scanResults;
174     WifiConfigCenter::GetInstance().GetWifiScanConfig()->GetScanInfoList(scanResults);
175     if (scanResults.empty()) {
176         WIFI_LOGE("scanResults is empty");
177         return;
178     }
179 
180     /* 计算同频邻频ap数 */
181     for (WifiScanInfo& result : scanResults) {
182         if (result.bssid.empty()) {
183             continue;
184         }
185         if (result.bssid == targetBssid) {
186             continue;
187         }
188         if (result.frequency == freq) {
189             apSamefreqCount++;
190             continue;
191         }
192         if (IsAdjacentChannel(freq, result.frequency, band)) {
193             apAdjafreqCount++;
194         }
195     }
196 
197     apDetailInfo.apSamefreq = apSamefreqCount;
198     apDetailInfo.apAdjafreq = apAdjafreqCount;
199 }
200 
UpdateForegroundBundleName(WifiCrowdsourcedDetailInfo & apDetailInfo)201 void WifiDataReportService::UpdateForegroundBundleName(WifiCrowdsourcedDetailInfo& apDetailInfo)
202 {
203     StaStateMachine* staStateMachinePtr = GetStaStateMachine();
204     if (staStateMachinePtr == nullptr) {
205         WIFI_LOGE("Failed to get staStateMachinePtr.");
206         return;
207     }
208     apDetailInfo.appName = staStateMachinePtr->curForegroundAppBundleName_;
209 }
210 
UpdateCrowdsourcedDetailInfo(WifiCrowdsourcedDetailInfo & apDetailInfo,const WifiLinkedInfo & linkedInfo,const WifiDeviceConfig & apDeviceInfo)211 void WifiDataReportService::UpdateCrowdsourcedDetailInfo(WifiCrowdsourcedDetailInfo& apDetailInfo,
212     const WifiLinkedInfo& linkedInfo, const WifiDeviceConfig& apDeviceInfo)
213 {
214     /* 更新上报时间 */
215     apDetailInfo.reporTimeStamp = std::time(nullptr);
216 
217     /* 更新 link 和 device 信息 */
218     apDetailInfo.lastHasInternetTime = apDeviceInfo.lastHasInternetTime;
219     apDetailInfo.connFailedCount = apDeviceInfo.connFailedCount;
220     apDetailInfo.isPortal = apDeviceInfo.isPortal;
221     apDetailInfo.apKeyMgmt = apDeviceInfo.keyMgmt;
222     apDetailInfo.band = apDeviceInfo.band;
223     apDetailInfo.frequency = apDeviceInfo.frequency;
224     apDetailInfo.rssi = linkedInfo.rssi;
225     apDetailInfo.ssid = linkedInfo.ssid;
226     apDetailInfo.bssid = linkedInfo.bssid;
227     apDetailInfo.channelWidth = linkedInfo.channelWidth;
228     apDetailInfo.isHiddenSSID = linkedInfo.ifHiddenSSID;
229     apDetailInfo.wifiStandard = linkedInfo.wifiStandard;
230     apDetailInfo.maxSupportedRxLinkSpeed = linkedInfo.maxSupportedRxLinkSpeed;
231     apDetailInfo.maxSupportedTxLinkSpeed = linkedInfo.maxSupportedTxLinkSpeed;
232     apDetailInfo.supportedWifiCategory = linkedInfo.supportedWifiCategory;
233     apDetailInfo.isMloConnected = linkedInfo.isMloConnected;
234     apDetailInfo.apMobile = linkedInfo.isDataRestricted; // 通过数据流量限制判断热点是否为手机连接
235     apDetailInfo.timeToDuraConn = connEventTimepInfo_.timeToDuraConn;
236     apDetailInfo.timeToSucConn = connEventTimepInfo_.timeToSucConn;
237 
238     /* 更新前台应用包名 */
239     UpdateForegroundBundleName(apDetailInfo);
240 
241     /* 更新同频 ap 和邻频 ap 数 */
242     UpdateSameAdjaFreqCount(apDetailInfo, linkedInfo.bssid, linkedInfo.frequency, linkedInfo.band);
243 }
244 
245 
ParseSignalPollInfo(WifiCrowdsourcedQoeInfo & parseInfo,const WifiSignalPollInfo & signalPollInfo)246 void WifiDataReportService::ParseSignalPollInfo(WifiCrowdsourcedQoeInfo& parseInfo,
247     const WifiSignalPollInfo& signalPollInfo)
248 {
249     /* 填充 QoeInfo 字段 */
250     parseInfo.txRate = signalPollInfo.txrate;
251     parseInfo.rxRate = signalPollInfo.rxrate;
252     parseInfo.noise = signalPollInfo.noise;
253     parseInfo.txPackets = signalPollInfo.txPackets;
254     parseInfo.rxPackets = signalPollInfo.rxPackets;
255     parseInfo.snr = signalPollInfo.snr;
256     parseInfo.chload = signalPollInfo.chload;
257     parseInfo.txBytes = signalPollInfo.txBytes;
258     parseInfo.rxBytes = signalPollInfo.rxBytes;
259     parseInfo.txFailed = signalPollInfo.txFailed;
260     parseInfo.chloadSelf = signalPollInfo.chloadSelf;
261     ParseSignalPollInfoEx(parseInfo, signalPollInfo); // 解析SignalPoll.Ext中的信息
262 }
263 
ParseSignalPollInfoEx(WifiCrowdsourcedQoeInfo & parseInfo,const WifiSignalPollInfo & signalPollInfo)264 void WifiDataReportService::ParseSignalPollInfoEx(WifiCrowdsourcedQoeInfo& parseInfo,
265     const WifiSignalPollInfo& signalPollInfo)
266 {
267     std::vector<uint8_t> signalPollInfoVec = signalPollInfo.ext;
268     if (signalPollInfoVec.size() < WifiDataConstants::QOE_INFO_LEN) {
269         return;
270     }
271     size_t index = 0;
272     index = index + WifiDataConstants::BEACON_RSSI_LEN; // 跳过 beacon rssi
273     parseInfo.txPpduCnt = GetUint32FromExt(signalPollInfoVec, index); // BadApTxPpduCnt
274 
275     index = index + sizeof(uint32_t);
276     parseInfo.txPpduRetryCnt = GetUint32FromExt(signalPollInfoVec, index); // BadApTxPpduRetryCnt
277 
278     index = index + sizeof(uint32_t);
279     parseInfo.txMcs = signalPollInfoVec[index]; // BadApTxMcs
280 
281     index = index + 1 + WifiDataConstants::AI_CW_LEN; // jump cw
282     std::vector<uint8_t> uldelayCdfUint8; // uldelay 序列
283     std::vector<uint16_t> uldelayCdfUint16;
284     uldelayCdfUint8.insert(uldelayCdfUint8.end(),
285         signalPollInfoVec.begin() + index, signalPollInfoVec.begin() + index + WifiDataConstants::CDF_RAW_LEN);
286     uldelayCdfUint16 = ConvertUint8ToUint16(uldelayCdfUint8);
287 
288     index = index + WifiDataConstants::CDF_RAW_LEN;
289     std::vector<uint8_t> txTimeCdfUint8; // txtime 序列
290     std::vector<uint16_t> txTimeCdfUint16;
291     txTimeCdfUint8.insert(txTimeCdfUint8.end(),
292         signalPollInfoVec.begin() + index, signalPollInfoVec.begin() + index + WifiDataConstants::CDF_RAW_LEN);
293     txTimeCdfUint16 = ConvertUint8ToUint16(txTimeCdfUint8);
294     /* 合并序列 */
295     std::vector<uint16_t> ulDelayCdf = SequenceMerge(uldelayCdfUint16);
296     std::vector<uint16_t> txTimeCdf = SequenceMerge(txTimeCdfUint16);
297 
298     parseInfo.ulDelayCdf = ulDelayCdf;
299     parseInfo.txTimeCdf = txTimeCdf;
300 }
301 
UpdateCrowdsourcedQoeInfo(WifiCrowdsourcedQoeInfo & apQoeInfo,const std::vector<WifiCrowdsourcedQoeInfo> & historyData)302 void WifiDataReportService::UpdateCrowdsourcedQoeInfo(WifiCrowdsourcedQoeInfo& apQoeInfo,
303     const std::vector<WifiCrowdsourcedQoeInfo>& historyData)
304 {
305     /* 累加 */
306     for (const auto& info : historyData) {
307         apQoeInfo.txRate += info.txRate;
308         apQoeInfo.rxRate += info.rxRate;
309         apQoeInfo.noise += info.noise;
310         apQoeInfo.txPackets += info.txPackets;
311         apQoeInfo.rxPackets += info.rxPackets;
312         apQoeInfo.snr += info.snr;
313         apQoeInfo.chload += info.chload;
314         apQoeInfo.txBytes = (apQoeInfo.txBytes > INT_MAX - info.txBytes) ? INT_MAX : apQoeInfo.txBytes + info.txBytes;
315         apQoeInfo.rxBytes = (apQoeInfo.rxBytes > INT_MAX - info.rxBytes) ? INT_MAX : apQoeInfo.rxBytes + info.rxBytes;
316         apQoeInfo.txFailed += info.txFailed;
317         apQoeInfo.chloadSelf += info.chloadSelf;
318         apQoeInfo.txPpduCnt += info.txPpduCnt;
319         apQoeInfo.txPpduRetryCnt += info.txPpduRetryCnt;
320         apQoeInfo.txMcs = info.txMcs;
321     }
322 
323     /* 计算均值 */
324     apQoeInfo.txRate /= WifiDataConstants::MAX_PUSH_COUNT;
325     apQoeInfo.rxRate /= WifiDataConstants::MAX_PUSH_COUNT;
326     apQoeInfo.noise /= WifiDataConstants::MAX_PUSH_COUNT;
327     apQoeInfo.txPackets /= WifiDataConstants::MAX_PUSH_COUNT;
328     apQoeInfo.rxPackets /= WifiDataConstants::MAX_PUSH_COUNT;
329     apQoeInfo.snr /= WifiDataConstants::MAX_PUSH_COUNT;
330     apQoeInfo.chload /= WifiDataConstants::MAX_PUSH_COUNT;
331     apQoeInfo.txBytes /= WifiDataConstants::MAX_PUSH_COUNT;
332     apQoeInfo.rxBytes /= WifiDataConstants::MAX_PUSH_COUNT;
333     apQoeInfo.txFailed /= WifiDataConstants::MAX_PUSH_COUNT;
334     apQoeInfo.chloadSelf /= WifiDataConstants::MAX_PUSH_COUNT;
335     apQoeInfo.txPpduCnt /= WifiDataConstants::MAX_PUSH_COUNT;
336     apQoeInfo.txPpduRetryCnt /= WifiDataConstants::MAX_PUSH_COUNT;
337     apQoeInfo.txMcs /= WifiDataConstants::MAX_PUSH_COUNT;
338 
339     /* 处理 vector 型数据,将每个 vector 中的元素相加 */
340     apQoeInfo.ulDelayCdf.resize(WifiDataConstants::CDF_LAST_LEN, 0); // 调整 mergedInfo.ulDelayCdf 的大小并初始化其元素为 0
341     apQoeInfo.txTimeCdf.resize(WifiDataConstants::CDF_LAST_LEN, 0); // 调整 mergedInfo.txTimeCdf 的大小并初始化其元素为 0
342 
343     /* 合并 ulDelayCdf, txTimeCdf */
344     for (const auto& info : historyData) {
345         if (info.ulDelayCdf.size() < WifiDataConstants::CDF_LAST_LEN ||
346             info.txTimeCdf.size() < WifiDataConstants::CDF_LAST_LEN) {
347             return;
348         }
349 
350         for (size_t i = 0; i < WifiDataConstants::CDF_LAST_LEN; ++i) {
351             apQoeInfo.ulDelayCdf[i] += info.ulDelayCdf[i];
352             apQoeInfo.txTimeCdf[i] += info.txTimeCdf[i];
353         }
354     }
355 }
356 
357 /* 事件上报 */
ReportApConnEventInfo(ConnReportReason reportReason,int targetNetworkId)358 void WifiDataReportService::ReportApConnEventInfo(ConnReportReason reportReason, int targetNetworkId)
359 {
360     std::lock_guard<std::mutex> lock(historyMutex_);
361     /* 检查断连标志位 */
362     if (disConnFlag_) {
363         return;
364     }
365 
366     StaStateMachine* staStateMachinePtr = GetStaStateMachine();
367     if (staStateMachinePtr == nullptr) {
368         WIFI_LOGE("Failed to get staStateMachinePtr.");
369         return;
370     }
371 
372     /* 获取 Ap deviece 信息 */
373     WifiDeviceConfig apDeviceInfo;
374     GetApDeviceInfo(targetNetworkId, staStateMachinePtr->m_instId, apDeviceInfo);
375 
376     /* 根据连接原因更改对应设置 */
377     switch (reportReason) {
378         case ConnReportReason::CONN_SUC_START: // 更新连接成功时间, 不改变标志位 disConnFlag_
379             UpdateApConnEventTimepInfo(ConnTimeType::STA_DHCP_SUC);
380             break;
381         case ConnReportReason::CONN_DISCONNECTED: // 更新正常断开连接时间, 改变标志位 disConnFlag_
382             UpdateApConnEventTimepInfo(ConnTimeType::STA_DISCONN_SUC);
383             disConnFlag_ = true;
384             break;
385         case ConnReportReason::CONN_ASSOCIATION_REJECTION: // 关联拒绝, 改变标志位 disConnFlag_
386         case ConnReportReason::CONN_ASSOCIATION_FULL: // 接入点满, 改变标志位 disConnFlag_
387             if (apDeviceInfo.connFailedCount < WifiDataConstants::CONN_FAILED_COUNT_THRESHOLD) {
388                 disConnFlag_ = true;
389                 return;
390             }
391             [[fallthrough]];
392         case ConnReportReason::CONN_WRONG_PASSWORD: // 密码错误, 改变标志位 disConnFlag_
393         case ConnReportReason::CONN_AUTHENTICATION_FAILURE: // 认证失败, 改变标志位 disConnFlag_
394         case ConnReportReason::CONN_DHCP_FAILURE: // Dhcp 失败, 改变标志位 disConnFlag_
395             disConnFlag_ = true;
396             break;
397         default:
398             break;
399     }
400     /* 调用众包接口 */
401     WifiCrowdsourcedInfo wifiCrowdsourcedInfo;
402     wifiCrowdsourcedInfo.apDetailInfo.reason = reportReason;
403     UpdateCrowdsourcedDetailInfo(wifiCrowdsourcedInfo.apDetailInfo, staStateMachinePtr->linkedInfo, apDeviceInfo);
404     if (staStateMachinePtr->enhanceService_ == nullptr || wifiCrowdsourcedInfo.apDetailInfo.ssid.empty()) {
405         return;
406     }
407     staStateMachinePtr->enhanceService_->CrowdsourcedDataReportInterface(wifiCrowdsourcedInfo);
408 }
409 
410 /* 周期上报 */
ReportQoeInfo(const WifiSignalPollInfo & signalPollInfo,ConnReportReason reportReason,int targetNetworkId)411 void WifiDataReportService::ReportQoeInfo(const WifiSignalPollInfo& signalPollInfo, ConnReportReason reportReason,
412     int targetNetworkId)
413 {
414     std::lock_guard<std::mutex> lock(historyMutex_);
415     StaStateMachine* staStateMachinePtr = GetStaStateMachine();
416     if (staStateMachinePtr == nullptr) {
417         WIFI_LOGE("Failed to get staStateMachinePtr.");
418         return;
419     }
420 
421     time_t now = std::time(nullptr);
422     auto it = lastPushTime_.find(staStateMachinePtr->linkedInfo.bssid);
423     time_t lastPush;
424     if (it != lastPushTime_.end()) {
425         /* 非第一次上报 qoe */
426         lastPush = it->second;  // 已存在,直接引用
427     } else {
428         /* 第一次上报 qoe */
429         lastPushTime_[staStateMachinePtr->linkedInfo.bssid] = 0;
430         lastPush = lastPushTime_[staStateMachinePtr->linkedInfo.bssid];
431     }
432 
433     /* 是否第一次上报或者距离上次上报间隔是否超过 DELAY_TIME */
434     if (lastPush != 0 && now - lastPush < WifiDataConstants::DELAY_TIME) {
435         return;
436     }
437 
438     WifiCrowdsourcedQoeInfo parseInfo;
439     ParseSignalPollInfo(parseInfo, signalPollInfo);
440     historyData_.push_back(parseInfo);
441 
442     if (historyData_.size() >= WifiDataConstants::MAX_PUSH_COUNT) {
443         WifiCrowdsourcedInfo wifiCrowdsourcedInfo;
444         wifiCrowdsourcedInfo.apDetailInfo.reason = reportReason;
445 
446         /* 获取 Ap deviece 信息 */
447         WifiDeviceConfig apDeviceInfo;
448         GetApDeviceInfo(targetNetworkId, staStateMachinePtr->m_instId, apDeviceInfo);
449 
450         UpdateCrowdsourcedDetailInfo(wifiCrowdsourcedInfo.apDetailInfo, // 更新 link 和 device 信息
451             staStateMachinePtr->linkedInfo, apDeviceInfo);
452 
453         UpdateCrowdsourcedQoeInfo(wifiCrowdsourcedInfo.apQoeInfo, historyData_); // 融合历史数据,更新 qoe 信息
454         historyData_.clear();
455 
456         if (staStateMachinePtr->enhanceService_ == nullptr) {
457             return;
458         }
459         staStateMachinePtr->enhanceService_->CrowdsourcedDataReportInterface(wifiCrowdsourcedInfo);
460         lastPushTime_[staStateMachinePtr->linkedInfo.bssid] = std::time(nullptr);
461     }
462 }
463 
464 } // namespace Wifi
465 } // namespace OHOS