• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 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 #include <sstream>
16 #include <fstream>
17 #include <climits>
18 #include <cstring>
19 #include <cstdio>
20 #include <algorithm>
21 #include <iostream>
22 #include <thread>
23 #include <unistd.h>
24 #include <string>
25 #include <regex>
26 #include <cstdarg>
27 #include <sys/time.h>
28 #include <sys/select.h>
29 #include <netinet/in.h>
30 #include "include/sp_utils.h"
31 #include "include/startup_delay.h"
32 #include "include/sp_log.h"
33 #include "include/sdk_data_recv.h"
34 #include "memory_collector.h"
35 #include "collect_result.h"
36 #include "include/sp_task.h"
37 #include "include/sp_utils.h"
38 #include "securec.h"
39 namespace OHOS {
40     namespace SmartPerf {
SdkDataRecv()41         SdkDataRecv::SdkDataRecv()
42         {
43             FD_ZERO(&readFds);
44         }
45 
ItemData()46         std::map<std::string, std::string> SdkDataRecv::ItemData()
47         {
48             std::map<std::string, std::string> ret;
49             GetSdkDataRealtimeData(ret);
50             LOGI("SdkDataRecv:ItemData map size(%u)", ret.size());
51             return ret;
52         }
53 
StartExecutionOnce(bool isPause)54         void SdkDataRecv::StartExecutionOnce(bool isPause)
55         {
56             if (!isPause) {
57                 sdkParams.startTime = SPUtils::GetCurTime();
58             }
59             OHOS::system::SetParameter("debug.smartperf.sdkdataenable", "1");
60             collectRunring = true;
61             WLOGI("Starting sdkdata collection in new thread");
62             if (th_.joinable()) {
63                 th_.join();
64             }
65             th_ = std::thread([this]() { ServerThread(); });
66         }
67 
FinishtExecutionOnce(bool isPause)68         void SdkDataRecv::FinishtExecutionOnce(bool isPause)
69         {
70             WLOGI("Disabling sdk data collection and resetting parameters");
71             OHOS::system::SetParameter("debug.smartperf.sdkdataenable", "0");
72             collectRunring = false;
73             if (listenFd != -1) {
74                 LOGD("Closing sdk data listenFd: %d", listenFd);
75                 close(listenFd);
76                 listenFd = -1;
77             }
78 
79             if (th_.joinable()) {
80                 th_.join();
81             }
82             if (isPause) {
83                 return;
84             }
85 
86             if (sdkVec_.empty()) {
87                 WLOGI("SDK data is not enabled or sdkvec is empty");
88                 return;
89             }
90 
91             LOGD("SDK data stop");
92             char outSdkDataDirChar[PATH_MAX] = {0x00};
93             if (realpath(filePath_.c_str(), outSdkDataDirChar) == nullptr) {
94                 WLOGE("data dir %s is nullptr", filePath_.c_str());
95                 return;
96             }
97             const std::string outSdkDataPath = std::string(outSdkDataDirChar) + "/sdk_data.csv";
98             std::ofstream outFile(outSdkDataPath.c_str(), std::ios::out | std::ios::trunc);
99             if (!outFile.is_open()) {
100                 WLOGE("data %s open failed", outSdkDataPath.c_str());
101                 return;
102             }
103             std::string title = "source,timestamp,eventName,enable,value\r";
104             outFile << title << std::endl;
105             for (const auto &item : sdkVec_) {
106                 outFile << item << std::endl;
107             }
108             outFile.close();
109             WLOGI("SDK data written successfully to %s", outSdkDataPath.c_str());
110         }
111 
CreateOhSocketServer(int basePort)112         int SdkDataRecv::CreateOhSocketServer(int basePort)
113         {
114             int i = 0;
115             int socketFd = 0;
116             struct sockaddr_in address;
117             const int reuse = 1;
118 
119             LOGD("Creating socket server on base port: %d", basePort);
120 
121             socketFd = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
122             if (socketFd < 0) {
123                 LOGE("Failed to create socket. Error: %d", errno);
124                 return -1;
125             }
126             setsockopt(socketFd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse));
127 
128             std::fill_n(reinterpret_cast<char*>(&address), sizeof(address), 0);
129             address.sin_family = AF_INET;
130             address.sin_addr.s_addr = inet_addr("127.0.0.1");
131 
132             for (i = 0; i < SOCKET_PORT_NUM_PER_TYPE; i++) {
133                 address.sin_port = htons(basePort + i);
134                 if (::bind(socketFd, reinterpret_cast<struct sockaddr *>(&address), sizeof(address)) == 0) {
135                     LOGD("Socket bound successfully to port: %d", basePort + i);
136                     break;
137                 }
138             }
139 
140             if (i >= SOCKET_PORT_NUM_PER_TYPE) {
141                 LOGE("Failed to bind socket after trying all ports starting from: %d", basePort);
142                 return -1;
143             }
144 
145             if (listen(socketFd, OH_SOCKET_MAX) < 0) {
146                 close(socketFd);
147                 LOGE("Failed to listen on socket. Error: %d", errno);
148                 return -1;
149             }
150 
151             LOGD("Listening on port %d, socket fd: %d", basePort + i, socketFd);
152             return socketFd;
153         }
ProcessData(std::string & message,ServerParams & params)154         std::string SdkDataRecv::ProcessData(std::string& message, ServerParams &params)
155         {
156             std::stringstream ss(message);
157             std::string enable;
158             std::string eventName;
159             std::string gameHead;
160             std::string item;
161             std::string realTimestamp;
162             std::string source;
163             std::string systime;
164             std::string smartFpsName;
165             std::string timestamp;
166             std::string value;
167             while (std::getline(ss, item, ',')) {
168                 std::stringstream itemSS(item);
169                 std::string first;
170                 std::string second;
171                 std::getline(itemSS, first, ':');
172                 std::getline(itemSS, second, ':');
173                 if (first == "src") {
174                     source = second;
175                 } else if (first == "para0") {
176                     eventName = second;
177                     if (second == "SmartFps") {
178                         smartFpsName = second;
179                     }
180                 } else if (first == "time") {
181                     realTimestamp = std::to_string(SPUtilesTye::StringToSometype<long long>(second) -
182                         sdkParams.startTime);
183                     timestamp = std::to_string(SPUtilesTye::StringToSometype<long long>(second) - params.startTime);
184                 } else if (first == "enable") {
185                     enable = second;
186                 } else if (first == "value") {
187                     value = second;
188                 } else if (first == "systime") {
189                     systime = second;
190                 }
191             }
192             item = source + "," + timestamp + "," + eventName + "," + enable + "," + value + "\r\n";
193             gameHead = source + "," + timestamp + "," + smartFpsName + "," + enable +
194                 "," + value + "," + systime + "\r\n";
195             GetSdkFpsAndSystime(gameHead);
196             std::unique_lock<std::mutex> lock(realtimeDataLock);
197             sdkDataRealtimeData += source + "_" + realTimestamp + "_" + eventName + "_" + enable + "_" + value + ";";
198             return item;
199         }
200 
OhDataReceive(int index,ServerParams & params)201         std::string SdkDataRecv::OhDataReceive(int index, ServerParams &params)
202         {
203             char receiveBuf[MSG_MAX_LEN];
204             std::string resStr;
205             int readLen = 0;
206             if ((readLen = read(params.receiveFd[index], receiveBuf, MSG_MAX_LEN)) <= 0) {
207                 close(params.receiveFd[index]);
208                 params.receiveFd[index] = -1;
209                 LOGE("Failed to read data from socket fd[%d]. Read length: %d, Error: %d", index, readLen, errno);
210                 return "";
211             }
212             if (readLen < MSG_MAX_LEN) {
213                 receiveBuf[readLen] = '\0';
214             } else {
215                 receiveBuf[MSG_MAX_LEN - 1] = '\0';
216             }
217             receiveBuffer = receiveBuf;
218             SocketCommandVerification(resStr, params);
219 
220             if (!resStr.empty() && resStr.back() == '\n') {
221                 resStr.pop_back();
222             }
223             return resStr;
224         }
225 
ServerThread()226         void SdkDataRecv::ServerThread()
227         {
228             for (int i = 0; i < OH_SOCKET_MAX; i++) {
229                 sdkParams.receiveFd[i] = -1;
230             }
231             sdkParams.startTime = SPUtils::GetCurTime();
232             sdkParams.serverFd = CreateOhSocketServer(OH_DATA_PORT);
233             if (sdkParams.serverFd < 0) {
234                 LOGE("Failed to create sdk data server, exiting...");
235                 return;
236             }
237 
238             if (pipe(sdkParams.pipFd) == -1) {
239                 LOGE("Failed to create sdk data pipe.");
240                 close(sdkParams.serverFd);
241                 return;
242             }
243             listenFd = sdkParams.pipFd[1];
244             RunServerThread(sdkParams);
245             LOGD("Sdk Data server thread exit.");
246         }
247 
RunServerThread(ServerParams & params)248         void SdkDataRecv::RunServerThread(ServerParams &params)
249         {
250             while (collectRunring) {
251                 SetUpFdSet(params);
252                 if (select(maxFd + 1, &readFds, nullptr, nullptr, nullptr) <= 0) {
253                     continue;
254                 }
255                 for (int i = 0; i < OH_SOCKET_MAX; i++) {
256                     HandleReceiveFd(i, params);
257                 }
258                 HandleServerFd(params);
259             }
260             CleanUpResources(params);
261         }
262 
SetUpFdSet(ServerParams & params)263         void SdkDataRecv::SetUpFdSet(ServerParams &params)
264         {
265             FD_ZERO(&readFds);
266             FD_SET(params.serverFd, &readFds);
267             FD_SET(params.pipFd[0], &readFds);
268 
269             maxFd = std::max(params.serverFd, params.pipFd[0]);
270             for (int i = 0; i < OH_SOCKET_MAX; i++) {
271                 if (params.receiveFd[i] >= 0) {
272                     FD_SET(params.receiveFd[i], &readFds);
273                     maxFd = std::max(maxFd, params.receiveFd[i]);
274                     LOGD("Sdk data adding receiveFd[%d]: %d to FD set", i, params.receiveFd[i]);
275                 }
276             }
277         }
278 
HandleReceiveFd(int i,ServerParams & params)279         void SdkDataRecv::HandleReceiveFd(int i, ServerParams &params)
280         {
281             if (params.receiveFd[i] >= 0 && FD_ISSET(params.receiveFd[i], &readFds)) {
282                 std::string data = OhDataReceive(i, params);
283                 if (SPTask::GetInstance().GetRecordState()) {
284                     sdkVec_.push_back(data);
285                 }
286             }
287         }
288 
HandleServerFd(ServerParams & params)289         void SdkDataRecv::HandleServerFd(ServerParams &params)
290         {
291             if (!FD_ISSET(params.serverFd, &readFds)) {
292                 return;
293             }
294 
295             int fd = accept(params.serverFd, nullptr, nullptr);
296             if (fd < 0) {
297                 return;
298             }
299 
300             for (int i = 0; i < OH_SOCKET_MAX; i++) {
301                 if (params.receiveFd[i] < 0) {
302                     params.receiveFd[i] = fd;
303                     if (fd > maxFd) {
304                         maxFd = fd;
305                     }
306                     break;
307                 }
308             }
309         }
310 
CleanUpResources(ServerParams & params)311         void SdkDataRecv::CleanUpResources(ServerParams &params)
312         {
313             if (params.serverFd != -1) {
314                 LOGD("Closing sdk data server socket fd: %d", params.serverFd);
315                 close(params.serverFd);
316                 params.serverFd = -1;
317             }
318             if (params.pipFd[0] != -1) {
319                 close(params.pipFd[0]);
320                 params.pipFd[0] = -1;
321             }
322             for (int i = 0; i < OH_SOCKET_MAX; i++) {
323                 if (params.receiveFd[i] != -1) {
324                     close(params.receiveFd[i]);
325                     params.receiveFd[i] = -1;
326                 }
327             }
328         }
329 
GetSdkDataRealtimeData(std::map<std::string,std::string> & dataMap)330         void SdkDataRecv::GetSdkDataRealtimeData(std::map<std::string, std::string> &dataMap)
331         {
332             std::unique_lock<std::mutex> lock(realtimeDataLock);
333             if (sdkDataRealtimeData.size() > 0) {
334                 dataMap.insert({"sdkData", sdkDataRealtimeData});
335                 sdkDataRealtimeData.clear();
336             }
337         }
338 
SocketCommandVerification(std::string & resStr,ServerParams & params)339         void SdkDataRecv::SocketCommandVerification(std::string &resStr, ServerParams &params)
340         {
341             bool processFlag = true;
342             while (processFlag) {
343                 size_t start = receiveBuffer.find('{');
344                 if (start == std::string::npos) {
345                     processFlag = false;
346                     break;
347                 }
348 
349                 size_t end = receiveBuffer.find('}', start);
350                 if (end == std::string::npos) {
351                     processFlag = false;
352                     break;
353                 }
354 
355                 std::size_t startPosition = start + 1;
356                 std::size_t length = end > start ? end - start - 1 : 0;
357                 if (startPosition >= receiveBuffer.size() || length > receiveBuffer.size() - startPosition) {
358                     processFlag = false;
359                     break;
360                 }
361 
362                 std::string message = receiveBuffer.substr(startPosition, length);
363                 resStr += ProcessData(message, params);
364 
365                 receiveBuffer.erase(0, end + 1);
366                 const int bufferSizeCheck = 2;
367                 if (receiveBuffer.size() <= bufferSizeCheck) {
368                     processFlag = false;
369                 }
370             }
371         }
372 
GetSdkFpsAndSystime(const std::string & sdkStr)373         void SdkDataRecv::GetSdkFpsAndSystime(const std::string &sdkStr)
374         {
375             std::stringstream ss(sdkStr);
376             std::string filed;
377             std::string curvalue;
378             std::string cursystem;
379             int indexFour = 4;
380             int indexFive = 5;
381             std::vector<std::string> vec;
382             size_t endPos = sdkStr.find("\r\n");
383             if (endPos != std::string::npos) {
384                 ss = std::stringstream(sdkStr.substr(0, endPos));
385             }
386 
387             while (getline(ss, filed, ',')) {
388                 vec.push_back(filed);
389             }
390             for (size_t i = 0; i < vec.size(); i++) {
391                 curvalue = vec[indexFour];
392                 cursystem = vec[indexFive];
393                 if (curvalue != "0" && cursystem != "0") {
394                     sdkFps = curvalue;
395                     sdkSystime = cursystem;
396                 }
397             }
398         }
399 
GetSdkFps() const400         std::string SdkDataRecv::GetSdkFps() const
401         {
402             return sdkFps;
403         }
404 
GetSdkSystime() const405         std::string SdkDataRecv::GetSdkSystime() const
406         {
407             return sdkSystime;
408         }
409 
SetFilePath(const std::string & path)410         void SdkDataRecv::SetFilePath(const std::string& path)
411         {
412             filePath_ = path;
413         }
414     }
415 }