1/*
2 * Copyright (c) 2022-2023 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 "net_stats_cached.h"
17
18#include <initializer_list>
19#include <list>
20#include <pthread.h>
21
22#include "net_conn_client.h"
23#include "net_mgr_log_wrapper.h"
24#include "net_stats_constants.h"
25#include "net_stats_data_handler.h"
26#include "net_stats_database_defines.h"
27#include "net_stats_database_helper.h"
28#include "netsys_controller.h"
29#include "bpf_stats.h"
30#include "ffrt_inner.h"
31
32namespace OHOS {
33namespace NetManagerStandard {
34using namespace NetStatsDatabaseDefines;
35namespace {
36constexpr const char *IFACE_LO = "lo";
37} // namespace
38
39int32_t NetStatsCached::StartCached()
40{
41    auto helper = std::make_unique<NetStatsDatabaseHelper>(NET_STATS_DATABASE_PATH);
42    auto ret = helper->CreateTable(VERSION_TABLE, VERSION_TABLE_CREATE_PARAM);
43    if (ret != NETMANAGER_SUCCESS) {
44        NETMGR_LOG_E("Create version table failed");
45        return STATS_ERR_CREATE_TABLE_FAIL;
46    }
47    ret = helper->CreateTable(UID_TABLE, UID_TABLE_CREATE_PARAM);
48    if (ret != NETMANAGER_SUCCESS) {
49        NETMGR_LOG_E("Create uid table failed");
50        return STATS_ERR_CREATE_TABLE_FAIL;
51    }
52    ret = helper->CreateTable(IFACE_TABLE, IFACE_TABLE_CREATE_PARAM);
53    if (ret != 0) {
54        NETMGR_LOG_E("Create iface table failed");
55        return STATS_ERR_CREATE_TABLE_FAIL;
56    }
57    ret = helper->CreateTable(UID_SIM_TABLE, UID_SIM_TABLE_CREATE_PARAM);
58    if (ret != 0) {
59        NETMGR_LOG_E("Create uid_sim table failed");
60        return STATS_ERR_CREATE_TABLE_FAIL;
61    }
62    helper->Upgrade();
63#ifndef UNITTEST_FORBID_FFRT
64    cacheTimer_ = std::make_unique<FfrtTimer>();
65    writeTimer_ = std::make_unique<FfrtTimer>();
66    cacheTimer_->Start(cycleThreshold_, [this]() { CacheStats(); });
67    writeTimer_->Start(STATS_PACKET_CYCLE_MS, [this]() { WriteStats(); });
68#endif
69    return ret;
70}
71
72void NetStatsCached::GetUidStatsCached(std::vector<NetStatsInfo> &uidStatsInfo)
73{
74    std::lock_guard<ffrt::mutex> lock(lock_);
75    uidStatsInfo.insert(uidStatsInfo.end(), stats_.GetUidStatsInfo().begin(), stats_.GetUidStatsInfo().end());
76}
77
78void NetStatsCached::GetUidSimStatsCached(std::vector<NetStatsInfo> &uidSimStatsInfo)
79{
80    std::lock_guard<ffrt::mutex> lock(lock_);
81    std::transform(stats_.GetUidSimStatsInfo().begin(), stats_.GetUidSimStatsInfo().end(),
82                   std::back_inserter(uidSimStatsInfo), [](NetStatsInfo &info) {
83                       NetStatsInfo tmpInfo = info;
84                       tmpInfo.uid_ = Sim_UID;
85                       return tmpInfo;
86                   });
87}
88
89void NetStatsCached::GetUidPushStatsCached(std::vector<NetStatsInfo> &uidPushStatsInfo)
90{
91    std::lock_guard<ffrt::mutex> lock(lock_);
92    uidPushStatsInfo.insert(uidPushStatsInfo.end(), uidPushStatsInfo_.begin(), uidPushStatsInfo_.end());
93}
94
95void NetStatsCached::GetAllPushStatsCached(std::vector<NetStatsInfo> &uidPushStatsInfo)
96{
97    std::lock_guard<ffrt::mutex> lock(lock_);
98    uidPushStatsInfo.insert(uidPushStatsInfo.end(), allPushStatsInfo_.begin(), allPushStatsInfo_.end());
99}
100
101void NetStatsCached::GetIfaceStatsCached(std::vector<NetStatsInfo> &ifaceStatsInfo)
102{
103    std::lock_guard<ffrt::mutex> lock(lock_);
104    ifaceStatsInfo.insert(ifaceStatsInfo.end(), stats_.GetIfaceStatsInfo().begin(), stats_.GetIfaceStatsInfo().end());
105}
106
107void NetStatsCached::SetAppStats(const PushStatsInfo &info)
108{
109    std::lock_guard<ffrt::mutex> lock(lock_);
110    NetStatsInfo stats;
111    stats.uid_ = info.uid_;
112    stats.iface_ = info.iface_;
113    stats.date_ = info.endTime_;
114    stats.rxBytes_ = info.rxBytes_;
115    stats.txBytes_ = info.txBytes_;
116    stats.rxPackets_ = info.rxBytes_ > 0 ? 1 : 0;
117    stats.txPackets_ = info.txBytes_ > 0 ? 1 : 0;
118    if (info.netBearType_ == BEARER_CELLULAR) {
119        stats.ident_ = std::to_string(info.simId_);
120    }
121    NETMGR_LOG_D("SetAppStats info=%{public}s", stats.UidData().c_str());
122    uidPushStatsInfo_.push_back(std::move(stats));
123}
124
125void NetStatsCached::GetKernelStats(std::vector<NetStatsInfo> &statsInfo)
126{
127    std::lock_guard<ffrt::mutex> lock(lock_);
128    std::vector<NetStatsInfo> allInfos;
129    NetsysController::GetInstance().GetAllStatsInfo(allInfos);
130    ifaceNameIdentMap_.Iterate([&allInfos](const std::string &k, const std::string &v) {
131        std::for_each(allInfos.begin(), allInfos.end(), [&k, &v](NetStatsInfo &item) {
132            if (item.iface_ == k) {
133                item.ident_ = v;
134            }
135        });
136    });
137    std::for_each(allInfos.begin(), allInfos.end(), [this, &statsInfo](NetStatsInfo &info) {
138        if (info.iface_ == IFACE_LO) {
139            return;
140        }
141        NetStatsInfo tmp = GetIncreasedStats(info);
142        if (tmp.HasNoData()) {
143            return;
144        }
145        tmp.date_ = CommonUtils::GetCurrentSecond();
146        statsInfo.push_back(std::move(tmp));
147    });
148    std::vector<NetStatsInfo> SimInfos;
149    NetsysController::GetInstance().GetAllSimStatsInfo(SimInfos);
150    ifaceNameIdentMap_.Iterate([&SimInfos](const std::string &k, const std::string &v) {
151        std::for_each(SimInfos.begin(), SimInfos.end(), [&k, &v](NetStatsInfo &item) {
152            if (item.iface_ == k) {
153                item.ident_ = v;
154            }
155        });
156    });
157    std::for_each(SimInfos.begin(), SimInfos.end(), [this, &statsInfo](NetStatsInfo &info) {
158        if (info.iface_ == IFACE_LO) {
159            return;
160        }
161        NetStatsInfo tmp = GetIncreasedSimStats(info);
162        if (tmp.HasNoData()) {
163            return;
164        }
165        tmp.date_ = CommonUtils::GetCurrentSecond();
166        tmp.uid_ = Sim_UID;
167        statsInfo.push_back(std::move(tmp));
168    });
169}
170
171NetStatsInfo NetStatsCached::GetIncreasedStats(const NetStatsInfo &info)
172{
173    auto findRet = std::find_if(lastUidStatsInfo_.begin(), lastUidStatsInfo_.end(),
174                                [&info](const NetStatsInfo &lastInfo) { return info.Equals(lastInfo); });
175    if (findRet == lastUidStatsInfo_.end()) {
176        return info;
177    }
178    return info - *findRet;
179}
180
181NetStatsInfo NetStatsCached::GetIncreasedSimStats(const NetStatsInfo &info)
182{
183    auto findRet = std::find_if(lastUidSimStatsInfo_.begin(), lastUidSimStatsInfo_.end(),
184                                [&info](const NetStatsInfo &lastInfo) { return info.Equals(lastInfo); });
185    if (findRet == lastUidSimStatsInfo_.end()) {
186        return info;
187    }
188    return info - *findRet;
189}
190
191void NetStatsCached::CacheUidStats()
192{
193    std::vector<NetStatsInfo> statsInfos;
194    NetsysController::GetInstance().GetAllStatsInfo(statsInfos);
195    if (statsInfos.empty()) {
196        NETMGR_LOG_W("No stats need to save");
197        return;
198    }
199
200    ifaceNameIdentMap_.Iterate([&statsInfos](const std::string &k, const std::string &v) {
201        std::for_each(statsInfos.begin(), statsInfos.end(), [&k, &v](NetStatsInfo &item) {
202            if (item.iface_ == k) {
203                item.ident_ = v;
204            }
205        });
206    });
207
208    std::for_each(statsInfos.begin(), statsInfos.end(), [this](NetStatsInfo &info) {
209        if (info.iface_ == IFACE_LO) {
210            return;
211        }
212        auto findRet = std::find_if(lastUidStatsInfo_.begin(), lastUidStatsInfo_.end(),
213                                    [this, &info](const NetStatsInfo &lastInfo) { return info.Equals(lastInfo); });
214        if (findRet == lastUidStatsInfo_.end()) {
215            stats_.PushUidStats(info);
216            return;
217        }
218        auto currentStats = info - *findRet;
219        stats_.PushUidStats(currentStats);
220    });
221    lastUidStatsInfo_.swap(statsInfos);
222}
223
224void NetStatsCached::CacheAppStats()
225{
226    std::vector<NetStatsInfo> pushInfos;
227    std::for_each(uidPushStatsInfo_.begin(), uidPushStatsInfo_.end(), [&pushInfos](NetStatsInfo &info) {
228        auto findRet = std::find_if(pushInfos.begin(), pushInfos.end(),
229                                    [&info](const NetStatsInfo &item) { return info.Equals(item); });
230        if (findRet == pushInfos.end()) {
231            pushInfos.push_back(info);
232            return;
233        }
234        *findRet += info;
235    });
236    std::for_each(pushInfos.begin(), pushInfos.end(), [this](auto &item) {
237        stats_.PushUidStats(item);
238        auto findRet = std::find_if(allPushStatsInfo_.begin(), allPushStatsInfo_.end(),
239                                    [&item](const NetStatsInfo &info) {
240                                        return info.Equals(item) && info.ident_ == item.ident_;
241                                    });
242        if (findRet == allPushStatsInfo_.end()) {
243            allPushStatsInfo_.push_back(item);
244            return;
245        }
246        *findRet += item;
247    });
248    uidPushStatsInfo_.clear();
249}
250
251void NetStatsCached::CacheUidSimStats()
252{
253    std::vector<NetStatsInfo> statsInfos;
254    NetsysController::GetInstance().GetAllSimStatsInfo(statsInfos);
255    if (statsInfos.empty()) {
256        NETMGR_LOG_W("No stats need to save");
257        return;
258    }
259
260    ifaceNameIdentMap_.Iterate([&statsInfos](const std::string &k, const std::string &v) {
261        std::for_each(statsInfos.begin(), statsInfos.end(), [&k, &v](NetStatsInfo &item) {
262            if (item.iface_ == k) {
263                item.ident_ = v;
264            }
265        });
266    });
267
268    std::for_each(statsInfos.begin(), statsInfos.end(), [this](NetStatsInfo &info) {
269        if (info.iface_ == IFACE_LO) {
270            return;
271        }
272        auto findRet = std::find_if(lastUidSimStatsInfo_.begin(), lastUidSimStatsInfo_.end(),
273                                    [this, &info](const NetStatsInfo &lastInfo) { return info.Equals(lastInfo); });
274        if (findRet == lastUidSimStatsInfo_.end()) {
275            stats_.PushUidSimStats(info);
276            return;
277        }
278        auto currentStats = info - *findRet;
279        stats_.PushUidSimStats(currentStats);
280    });
281    lastUidSimStatsInfo_.swap(statsInfos);
282}
283
284void NetStatsCached::CacheIfaceStats()
285{
286    std::vector<std::string> ifNameList = NetsysController::GetInstance().InterfaceGetList();
287    std::for_each(ifNameList.begin(), ifNameList.end(), [this](const auto &ifName) {
288        if (ifName == IFACE_LO) {
289            return;
290        }
291        NetStatsInfo statsInfo;
292        statsInfo.iface_ = ifName;
293        NetsysController::GetInstance().GetIfaceStats(statsInfo.rxBytes_,
294                                                      static_cast<uint32_t>(StatsType::STATS_TYPE_RX_BYTES), ifName);
295        NetsysController::GetInstance().GetIfaceStats(statsInfo.rxPackets_,
296                                                      static_cast<uint32_t>(StatsType::STATS_TYPE_RX_PACKETS), ifName);
297        NetsysController::GetInstance().GetIfaceStats(statsInfo.txBytes_,
298                                                      static_cast<uint32_t>(StatsType::STATS_TYPE_TX_BYTES), ifName);
299        NetsysController::GetInstance().GetIfaceStats(statsInfo.txPackets_,
300                                                      static_cast<uint32_t>(StatsType::STATS_TYPE_TX_PACKETS), ifName);
301        auto findRet = lastIfaceStatsMap_.find(ifName);
302        if (findRet == lastIfaceStatsMap_.end()) {
303            stats_.PushIfaceStats(statsInfo);
304            lastIfaceStatsMap_[ifName] = statsInfo;
305            return;
306        }
307        auto currentStats = statsInfo - findRet->second;
308        stats_.PushIfaceStats(currentStats);
309        lastIfaceStatsMap_[ifName] = statsInfo;
310    });
311}
312
313void NetStatsCached::CacheStats()
314{
315    std::lock_guard<ffrt::mutex> lock(lock_);
316    CacheUidStats();
317    CacheAppStats();
318    CacheUidSimStats();
319    CacheIfaceStats();
320}
321
322void NetStatsCached::WriteStats()
323{
324    std::lock_guard<ffrt::mutex> lock(lock_);
325    WriteUidStats();
326    WriteUidSimStats();
327    WriteIfaceStats();
328}
329void NetStatsCached::WriteIfaceStats()
330{
331    if (!(CheckIfaceStor() || isForce_)) {
332        return;
333    }
334    auto handler = std::make_unique<NetStatsDataHandler>();
335    handler->WriteStatsData(stats_.GetIfaceStatsInfo(), NetStatsDatabaseDefines::IFACE_TABLE);
336    handler->DeleteByDate(NetStatsDatabaseDefines::IFACE_TABLE, 0, CommonUtils::GetCurrentSecond() - dateCycle_);
337    stats_.ResetIfaceStats();
338}
339
340void NetStatsCached::WriteUidStats()
341{
342    if (!(CheckUidStor() || isForce_)) {
343        return;
344    }
345    std::for_each(stats_.GetUidStatsInfo().begin(), stats_.GetUidStatsInfo().end(), [this](NetStatsInfo &info) {
346        if (info.uid_ == uninstalledUid_) {
347            info.flag_ = STATS_DATA_FLAG_UNINSTALLED;
348        }
349    });
350    auto handler = std::make_unique<NetStatsDataHandler>();
351    handler->WriteStatsData(stats_.GetUidStatsInfo(), NetStatsDatabaseDefines::UID_TABLE);
352    handler->DeleteByDate(NetStatsDatabaseDefines::UID_TABLE, 0, CommonUtils::GetCurrentSecond() - dateCycle_);
353    stats_.ResetUidStats();
354}
355
356void NetStatsCached::WriteUidSimStats()
357{
358    if (!(CheckUidSimStor() || isForce_)) {
359        return;
360    }
361    std::for_each(stats_.GetUidSimStatsInfo().begin(), stats_.GetUidSimStatsInfo().end(), [this](NetStatsInfo &info) {
362        if (info.uid_ == uninstalledUid_) {
363            info.flag_ = STATS_DATA_FLAG_UNINSTALLED;
364        }
365    });
366    auto handler = std::make_unique<NetStatsDataHandler>();
367    handler->WriteStatsData(stats_.GetUidSimStatsInfo(), NetStatsDatabaseDefines::UID_SIM_TABLE);
368    handler->DeleteByDate(NetStatsDatabaseDefines::UID_SIM_TABLE, 0, CommonUtils::GetCurrentSecond() - dateCycle_);
369    stats_.ResetUidSimStats();
370}
371
372void NetStatsCached::LoadIfaceNameIdentMaps()
373{
374    int32_t ret = NetConnClient::GetInstance().GetIfaceNameIdentMaps(NetBearType::BEARER_CELLULAR, ifaceNameIdentMap_);
375    if (ret != NETMANAGER_SUCCESS) {
376        NETMGR_LOG_E("GetIfaceNameIdentMaps error. ret=%{public}d", ret);
377    }
378}
379
380void NetStatsCached::SetCycleThreshold(uint32_t threshold)
381{
382    NETMGR_LOG_D("Current cycle threshold has changed current is : %{public}d", threshold);
383    cycleThreshold_ = threshold;
384#ifndef UNITTEST_FORBID_FFRT
385    cacheTimer_ = std::make_unique<FfrtTimer>();
386    cacheTimer_->Start(cycleThreshold_, [this]() { CacheStats(); });
387#endif
388}
389
390void NetStatsCached::ForceUpdateStats()
391{
392    isForce_ = true;
393    std::function<void()> netCachedStats = [this] () {
394        CacheStats();
395        WriteStats();
396        isForce_ = false;
397        LoadIfaceNameIdentMaps();
398    };
399    ffrt::submit(std::move(netCachedStats), {}, {}, ffrt::task_attr().name("NetCachedStats"));
400}
401
402void NetStatsCached::ForceDeleteStats(uint32_t uid)
403{
404    NETMGR_LOG_I("ForceDeleteStats Enter uid[%{public}u]", uid);
405    auto ret = NetsysController::GetInstance().DeleteStatsInfo(uid);
406    if (ret != NETMANAGER_SUCCESS) {
407        NETMGR_LOG_E("ForceDeleteStats DeleteStatsInfo failed. ret is %{public}d", ret);
408    }
409    ret = NetsysController::GetInstance().DeleteSimStatsInfo(uid);
410    if (ret != NETMANAGER_SUCCESS) {
411        NETMGR_LOG_E("ForceDeleteStats DeleteSimStatsInfo failed. ret is %{public}d", ret);
412    }
413
414    std::lock_guard<ffrt::mutex> lock(lock_);
415    stats_.ResetUidStats(uid);
416    stats_.ResetUidSimStats(uid);
417    lastUidStatsInfo_.erase(std::remove_if(lastUidStatsInfo_.begin(), lastUidStatsInfo_.end(),
418                                           [uid](const auto &item) { return item.uid_ == uid; }),
419                            lastUidStatsInfo_.end());
420    lastUidSimStatsInfo_.erase(std::remove_if(lastUidSimStatsInfo_.begin(), lastUidSimStatsInfo_.end(),
421                                              [uid](const auto &item) { return item.uid_ == uid; }),
422                               lastUidSimStatsInfo_.end());
423    uidPushStatsInfo_.erase(std::remove_if(uidPushStatsInfo_.begin(), uidPushStatsInfo_.end(),
424                                           [uid](const auto &item) { return item.uid_ == uid; }),
425                            uidPushStatsInfo_.end());
426}
427
428void NetStatsCached::ForceArchiveStats(uint32_t uid)
429{
430    std::function<void()> netCachedStats = [this, uid]() {
431        CacheStats();
432        {
433            std::lock_guard<ffrt::mutex> lock(lock_);
434            isForce_ = true;
435            uninstalledUid_ = uid;
436            WriteUidStats();
437            WriteUidSimStats();
438            uninstalledUid_ = -1;
439            isForce_ = false;
440        }
441        ForceDeleteStats(uid);
442    };
443    ffrt::submit(std::move(netCachedStats), {}, {}, ffrt::task_attr().name("NetForceArchiveStats"));
444}
445
446void NetStatsCached::Reset() {}
447
448} // namespace NetManagerStandard
449} // namespace OHOS
450