• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) Huawei Technologies Co., Ltd. 2021. All rights reserved.
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 #include "network_plugin.h"
16 
17 #include <string>
18 #include <sys/stat.h>
19 
20 #include "buffer_splitter.h"
21 #include "network_plugin_result.pbencoder.h"
22 #include "securec.h"
23 
24 namespace {
25 using namespace OHOS::Developtools::Profiler;
26 constexpr size_t READ_BUFFER_SIZE = 1024 * 16;
27 const std::string DEFAULT_NET_PATH("/proc/net/xt_qtaguid/stats");
28 } // namespace
29 
NetworkPlugin()30 NetworkPlugin::NetworkPlugin()
31     : buffer_(new (std::nothrow) uint8_t[READ_BUFFER_SIZE]), fp_(nullptr, nullptr)
32 {
33     pidUid_.clear();
34 }
35 
Start(const uint8_t * configData,uint32_t configSize)36 int NetworkPlugin::Start(const uint8_t* configData, uint32_t configSize)
37 {
38     CHECK_NOTNULL(buffer_, -1, "%s:NetworkPlugin, buffer_ is null", __func__);
39 
40     if (protoConfig_.ParseFromArray(configData, configSize) <= 0) {
41         PROFILER_LOG_ERROR(LOG_CORE, "%s:NetworkPlugin, parseFromArray failed!", __func__);
42         return -1;
43     }
44 
45     for (int i = 0; i < protoConfig_.pid().size(); i++) {
46         int32_t pid = protoConfig_.pid(i);
47         pidUid_.emplace(pid, GetUid(pid));
48     }
49 
50     PROFILER_LOG_INFO(LOG_CORE, "%s:NetworkPlugin, start success!", __func__);
51 
52     return 0;
53 }
54 
WriteNetWorkData(T & networkDatasProto)55 template <typename T> bool NetworkPlugin::WriteNetWorkData(T& networkDatasProto)
56 {
57     std::string file = GetRateNodePath();
58     if (protoConfig_.test_file() != "") {
59         file = protoConfig_.test_file();
60     }
61 
62     struct stat s;
63     lstat(file.c_str(), &s);
64     CHECK_TRUE(!S_ISDIR(s.st_mode), false, "%s:path(%s) is directory, no data to report", __func__, file.c_str());
65 
66     char realPath[PATH_MAX + 1] = {0};
67     CHECK_TRUE((file.length() < PATH_MAX) && (realpath(file.c_str(), realPath) != nullptr), false,
68                "%s:path is invalid: %s, errno=%d", __func__, file.c_str(), errno);
69     fp_ = std::unique_ptr<FILE, int (*)(FILE*)>(fopen(realPath, "r"), fclose);
70     CHECK_NOTNULL(fp_, false, "%s:NetworkPlugin, open(%s) Failed, errno(%d)", __func__, file.c_str(), errno);
71 
72     if (protoConfig_.pid().size() > 0) {
73         for (int i = 0; i < protoConfig_.pid().size(); i++) {
74             auto* info = networkDatasProto.add_networkinfo();
75             int32_t pid = protoConfig_.pid(i);
76             NetworkCell dataCell = {0};
77             ReadTxRxBytes(pid, dataCell);
78             // set proto
79             for (auto& it : dataCell.details) {
80                 auto* data = info->add_details();
81                 data->set_tx_bytes(it.tx);
82                 data->set_rx_bytes(it.rx);
83                 data->set_type(it.type);
84             }
85             info->set_pid(pid);
86             info->set_tx_bytes(dataCell.tx);
87             info->set_rx_bytes(dataCell.rx);
88             info->set_tv_sec(dataCell.ts.tv_sec);
89             info->set_tv_nsec(dataCell.ts.tv_nsec);
90         }
91     } else if (protoConfig_.test_file() != "") { // test data
92         NetSystemData systemData = {};
93         ReadSystemTxRxBytes(systemData);
94         static int randNum = 0;
95         randNum++;
96         auto* systemInfo = networkDatasProto.mutable_network_system_info();
97         for (auto& it : systemData.details) {
98             auto* data = systemInfo->add_details();
99             data->set_rx_bytes(it.rxBytes + randNum * RX_BYTES_INDEX);
100             data->set_rx_packets(it.rxPackets + randNum * RX_PACKETS_INDEX);
101             data->set_tx_bytes(it.txBytes + randNum * TX_BYTES_INDEX);
102             data->set_tx_packets(it.txPackets + randNum * TX_PACKETS_INDEX);
103             data->set_type(it.type);
104         }
105         systemInfo->set_tv_sec(systemData.ts.tv_sec);
106         systemInfo->set_tv_nsec(systemData.ts.tv_nsec);
107         systemInfo->set_rx_bytes(systemData.rxBytes + (randNum * RX_BYTES_INDEX * systemData.details.size()));
108         systemInfo->set_rx_packets(systemData.rxPackets + (randNum * RX_PACKETS_INDEX * systemData.details.size()));
109         systemInfo->set_tx_bytes(systemData.txBytes + (randNum * TX_BYTES_INDEX * systemData.details.size()));
110         systemInfo->set_tx_packets(systemData.txPackets + (randNum * TX_PACKETS_INDEX * systemData.details.size()));
111     } else { // real data
112         NetSystemData systemData = {};
113         ReadSystemTxRxBytes(systemData);
114         auto* systemInfo = networkDatasProto.mutable_network_system_info();
115         for (auto& it : systemData.details) {
116             auto* data = systemInfo->add_details();
117             data->set_rx_bytes(it.rxBytes);
118             data->set_rx_packets(it.rxPackets);
119             data->set_tx_bytes(it.txBytes);
120             data->set_tx_packets(it.txPackets);
121             data->set_type(it.type);
122         }
123         systemInfo->set_tv_sec(systemData.ts.tv_sec);
124         systemInfo->set_tv_nsec(systemData.ts.tv_nsec);
125         systemInfo->set_rx_bytes(systemData.rxBytes);
126         systemInfo->set_rx_packets(systemData.rxPackets);
127         systemInfo->set_tx_bytes(systemData.txBytes);
128         systemInfo->set_tx_packets(systemData.txPackets);
129     }
130 
131     return true;
132 }
133 
ReportOptimize(RandomWriteCtx * randomWrite)134 int NetworkPlugin::ReportOptimize(RandomWriteCtx* randomWrite)
135 {
136     ProtoEncoder::NetworkDatas dataProto(randomWrite);
137     CHECK_TRUE(WriteNetWorkData(dataProto), -1, "%s:write network data failed", __func__);
138 
139     int msgSize = dataProto.Finish();
140     return msgSize;
141 }
142 
Report(uint8_t * data,uint32_t dataSize)143 int NetworkPlugin::Report(uint8_t* data, uint32_t dataSize)
144 {
145     NetworkDatas dataProto;
146     CHECK_TRUE(WriteNetWorkData(dataProto), -1, "%s:write network data failed", __func__);
147 
148     uint32_t length = dataProto.ByteSizeLong();
149     if (length > dataSize) {
150         return -length;
151     }
152     if (dataProto.SerializeToArray(data, length) > 0) {
153         return length;
154     }
155     return 0;
156 }
157 
Stop()158 int NetworkPlugin::Stop()
159 {
160     buffer_ = nullptr;
161     fp_ = nullptr;
162     pidUid_.clear();
163 
164     PROFILER_LOG_INFO(LOG_CORE, "%s:NetworkPlugin, stop success!", __func__);
165     return 0;
166 }
167 
GetRateNodePath()168 std::string NetworkPlugin::GetRateNodePath()
169 {
170     std::string name = "";
171 
172     if (!fileForTest_.empty()) {
173         name = fileForTest_ + DEFAULT_NET_PATH;
174         return name;
175     }
176     if (access(DEFAULT_NET_PATH.c_str(), F_OK) == 0) {
177         name = DEFAULT_NET_PATH;
178     }
179     return name;
180 }
181 
GetUid(int32_t pid)182 int32_t NetworkPlugin::GetUid(int32_t pid)
183 {
184     CHECK_TRUE(pid > 0, -1, "%s:NetworkPlugin, check param fail, pid less than 0!", __func__);
185 
186     char* end = nullptr;
187     std::string path = std::string("/proc/") + std::to_string(pid) + std::string("/status");
188     if (!fileForTest_.empty()) {
189         path = fileForTest_ + std::string("/proc/") + std::to_string(pid) + std::string("/status");
190     }
191     std::ifstream input(path, std::ios::in);
192     if (input.fail()) {
193         const int bufSize = 256;
194         char buf[bufSize] = { 0 };
195         strerror_r(errno, buf, bufSize);
196         PROFILER_LOG_ERROR(LOG_CORE, "%s:NetworkPlugin, open %s failed, errno(%s)", __func__, path.c_str(), buf);
197         return -1;
198     }
199     do {
200         if (!input.good()) {
201             return -1;
202         }
203         std::string line;
204         getline(input, line);
205         if (!strncmp(line.c_str(), "Uid:", strlen("Uid:"))) {
206             std::string str = line.substr(strlen("Uid:\t"));
207             PROFILER_LOG_INFO(LOG_CORE, "%s:NetworkPlugin, line(%s), str(%s)", __func__, line.c_str(), str.c_str());
208             return strtol(str.c_str(), &end, DEC_BASE);
209         }
210     } while (!input.eof());
211     input.close();
212 
213     return -1;
214 }
215 
ReadTxRxBytes(int32_t pid,NetworkCell & cell)216 bool NetworkPlugin::ReadTxRxBytes(int32_t pid, NetworkCell &cell)
217 {
218     int32_t uid = pidUid_.at(pid);
219     CHECK_NOTNULL(fp_.get(), false, "%s:NetworkPlugin, fp_ is null", __func__);
220     int ret = fseek(fp_.get(), 0, SEEK_SET);
221     CHECK_TRUE(ret == 0, false, "%s:NetworkPlugin, fseek failed, error(%d)!", __func__, errno);
222     size_t rsize = static_cast<size_t>(fread(buffer_.get(), sizeof(char), READ_BUFFER_SIZE - 1, fp_.get()));
223     buffer_.get()[rsize] = '\0';
224     CHECK_TRUE(rsize >= 0, false, "%s:NetworkPlugin, read failed, errno(%d)", __func__, errno);
225     char* end = nullptr;
226     BufferSplitter totalbuffer((const char*)buffer_.get(), rsize + 1);
227     do {
228         int index = 0;
229         NetDetails cache = {0};
230         char tmp[TX_BYTES_INDEX + 1] = {0};
231         while (totalbuffer.NextWord(' ')) {
232             index++;
233             if (totalbuffer.CurWord() == nullptr) {
234                 continue;
235             }
236             if (index == IFACE_INDEX && !strncmp(totalbuffer.CurWord(), "lo", strlen("lo"))) {
237                 break;
238             }
239             if (index == IFACE_INDEX &&
240                 strncpy_s(tmp, sizeof(tmp), totalbuffer.CurWord(), totalbuffer.CurWordSize()) == EOK) {
241                 cache.type = tmp;
242             }
243             uint64_t value = static_cast<uint64_t>(strtoull(totalbuffer.CurWord(), &end, DEC_BASE));
244             CHECK_TRUE(value >= 0, false, "%s:NetworkPlugin, strtoull value failed", __func__);
245             if ((index == UID_INDEX) && (uid != static_cast<int32_t>(value))) {
246                 break;
247             }
248             if (index == RX_BYTES_INDEX) {
249                 uint64_t rxBytes = value;
250                 cache.rx = rxBytes;
251                 cell.rx += rxBytes;
252             }
253             if (index == TX_BYTES_INDEX) {
254                 uint64_t txBytes = value;
255                 cache.tx = txBytes;
256                 cell.tx += txBytes;
257                 AddNetDetails(cell, cache);
258             }
259         }
260     } while (totalbuffer.NextLine());
261 
262     clock_gettime(CLOCK_REALTIME, &cell.ts);
263 
264     return true;
265 }
266 
AddNetDetails(NetworkCell & cell,NetDetails & data)267 void NetworkPlugin::AddNetDetails(NetworkCell& cell, NetDetails& data)
268 {
269     bool finded = false;
270 
271     // 处理重复数据
272     for (auto it = cell.details.begin(); it != cell.details.end(); it++) {
273         if (it->type == data.type) {
274             it->tx += data.tx;
275             it->rx += data.rx;
276             finded = true;
277         }
278     }
279 
280     if (!finded) {
281         cell.details.push_back(data);
282     }
283 }
284 
ReadSystemTxRxBytes(NetSystemData & systemData)285 bool NetworkPlugin::ReadSystemTxRxBytes(NetSystemData &systemData)
286 {
287     CHECK_NOTNULL(fp_.get(), false, "%s:NetworkPlugin, fp_ is null", __func__);
288     int ret = fseek(fp_.get(), 0, SEEK_SET);
289     CHECK_TRUE(ret == 0, false, "%s:NetworkPlugin, fseek failed, error(%d)!", __func__, errno);
290     size_t rsize = static_cast<size_t>(fread(buffer_.get(), sizeof(char), READ_BUFFER_SIZE - 1, fp_.get()));
291     buffer_.get()[rsize] = '\0';
292     CHECK_TRUE(rsize >= 0, false, "%s:NetworkPlugin, read failed, errno(%d)", __func__, errno);
293     char* end = nullptr;
294     BufferSplitter totalbuffer((const char*)buffer_.get(), rsize + 1);
295     do {
296         int index = 0;
297         NetSystemDetails systemCache = {};
298         char tmp[TX_BYTES_INDEX + 1] = "";
299         while (totalbuffer.NextWord(' ')) {
300             index++;
301             if (totalbuffer.CurWord() == nullptr) {
302                 continue;
303             }
304             if (index == IFACE_INDEX && !strncmp(totalbuffer.CurWord(), "lo", strlen("lo"))) {
305                 break;
306             }
307             if (index == IFACE_INDEX &&
308                 strncpy_s(tmp, sizeof(tmp), totalbuffer.CurWord(), totalbuffer.CurWordSize()) == EOK) {
309                 systemCache.type = tmp;
310             }
311             if (strcmp(systemCache.type.c_str(), "iface") == 0) {
312                 break;
313             }
314             uint64_t value = static_cast<uint64_t>(strtoull(totalbuffer.CurWord(), &end, DEC_BASE));
315             CHECK_TRUE(value >= 0, false, "%s:NetworkPlugin, strtoull value failed", __func__);
316             if (index == RX_BYTES_INDEX) {
317                 uint64_t rxBytes = value;
318                 systemCache.rxBytes = rxBytes;
319                 systemData.rxBytes += rxBytes;
320             } else if (index == RX_PACKETS_INDEX) {
321                 uint64_t rxPackets = value;
322                 systemCache.rxPackets = rxPackets;
323                 systemData.rxPackets += rxPackets;
324             } else if (index == TX_BYTES_INDEX) {
325                 uint64_t txBytes = value;
326                 systemCache.txBytes = txBytes;
327                 systemData.txBytes += txBytes;
328             } else if (index == TX_PACKETS_INDEX) {
329                 uint64_t txPackets = value;
330                 systemCache.txPackets = txPackets;
331                 systemData.txPackets += txPackets;
332                 AddNetSystemDetails(systemData, systemCache);
333             }
334         }
335     } while (totalbuffer.NextLine());
336 
337     clock_gettime(CLOCK_REALTIME, &systemData.ts);
338 
339     return true;
340 }
341 
AddNetSystemDetails(NetSystemData & systemData,NetSystemDetails & data)342 void NetworkPlugin::AddNetSystemDetails(NetSystemData& systemData, NetSystemDetails& data)
343 {
344     bool finded = false;
345 
346     // 处理重复数据
347     for (auto it = systemData.details.begin(); it != systemData.details.end(); it++) {
348         if (it->type == data.type) {
349             it->rxBytes += data.rxBytes;
350             it->rxPackets += data.rxPackets;
351             it->txBytes += data.txBytes;
352             it->txPackets += data.txPackets;
353             finded = true;
354         }
355     }
356 
357     if (!finded) {
358         systemData.details.push_back(data);
359     }
360 }
361