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 <algorithm>
16 #include <array>
17 #include <chrono>
18 #include <cstdio>
19 #include <cstring>
20 #include <ctime>
21 #include <fcntl.h>
22 #include <iostream>
23 #include <memory>
24 #include <optional>
25 #include <regex>
26 #include <sstream>
27 #include <sys/mman.h>
28 #include <sys/prctl.h>
29 #include <sys/stat.h>
30 #include <thread>
31 #include <unistd.h>
32 #include <dirent.h>
33
34 #include <securec.h>
35 #include <hilog/log.h>
36 #include <hilog_common.h>
37 #include <log_utils.h>
38 #include <properties.h>
39
40 #include "log_data.h"
41 #include "log_buffer.h"
42 #include "log_kmsg.h"
43
44 #include "service_controller.h"
45
46 namespace OHOS {
47 namespace HiviewDFX {
48 using namespace std;
49 static const string LOG_PERSISTER_DIR = HILOG_FILE_DIR;
50 static constexpr uint16_t DEFAULT_LOG_TYPES = ((0b01 << LOG_APP) | (0b01 << LOG_CORE) | (0b01 << LOG_INIT));
51 static constexpr uint16_t DEFAULT_REMOVE_LOG_TYPES = ((0b01 << LOG_APP) | (0b01 << LOG_CORE));
52 static constexpr uint32_t DEFAULT_PERSIST_FILE_NUM = 10;
53 static constexpr uint32_t DEFAULT_PERSIST_FILE_SIZE = (4 * 1024 * 1024);
54 static constexpr uint32_t DEFAULT_PERSIST_NORMAL_JOB_ID = 1;
55 static constexpr uint32_t DEFAULT_PERSIST_KMSG_JOB_ID = 2;
56 static constexpr int INFO_SUFFIX = 5;
57 static const uid_t SHELL_UID = 2000;
58 static const uid_t ROOT_UID = 0;
59
ServiceController(std::unique_ptr<Socket> communicationSocket,LogCollector & collector,HilogBuffer & buffer)60 ServiceController::ServiceController(std::unique_ptr<Socket> communicationSocket,
61 LogCollector& collector, HilogBuffer& buffer)
62 : m_communicationSocket(std::move(communicationSocket))
63 , m_logCollector(collector)
64 , m_hilogBuffer(buffer)
65 {
66 m_bufReader = m_hilogBuffer.CreateBufReader([this]() { NotifyForNewData(); });
67 }
68
~ServiceController()69 ServiceController::~ServiceController()
70 {
71 m_hilogBuffer.RemoveBufReader(m_bufReader);
72 m_notifyNewDataCv.notify_all();
73 }
74
IsValidFileName(const std::string & strFileName)75 inline bool IsValidFileName(const std::string& strFileName)
76 {
77 // File name shouldn't contain "[\\/:*?\"<>|]"
78 std::regex regExpress("[\\/:*?\"<>|]");
79 bool bValid = !std::regex_search(strFileName, regExpress);
80 return bValid;
81 }
82
GetMsgHeader(MsgHeader & hdr)83 int ServiceController::GetMsgHeader(MsgHeader& hdr)
84 {
85 if (!m_communicationSocket) {
86 std::cerr << " Invalid socket handler!" << std::endl;
87 return RET_FAIL;
88 }
89 int ret = m_communicationSocket->Read(reinterpret_cast<char *>(&hdr), sizeof(MsgHeader));
90 if (ret < static_cast<int>(sizeof(MsgHeader))) {
91 std::cerr << "Read MsgHeader error!" << std::endl;
92 return RET_FAIL;
93 }
94 return RET_SUCCESS;
95 }
96
GetRqst(const MsgHeader & hdr,char * rqst,int expectedLen)97 int ServiceController::GetRqst(const MsgHeader& hdr, char* rqst, int expectedLen)
98 {
99 if (hdr.len != expectedLen) {
100 std::cout << "Invalid MsgHeader! hdr.len:" << hdr.len << ", expectedLen:" << expectedLen << endl;
101 return RET_FAIL;
102 }
103 int ret = m_communicationSocket->Read(rqst, hdr.len);
104 if (ret <= 0) {
105 std::cout << "Read socket error! " << ret << endl;
106 return RET_FAIL;
107 }
108 return RET_SUCCESS;
109 }
110
WriteRspHeader(IoctlCmd cmd,size_t len)111 void ServiceController::WriteRspHeader(IoctlCmd cmd, size_t len)
112 {
113 MsgHeader header = {MSG_VER, static_cast<uint8_t>(cmd), 0, static_cast<uint16_t>(len)};
114 (void)m_communicationSocket->Write(reinterpret_cast<char*>(&header), sizeof(MsgHeader));
115 return;
116 }
117
WriteErrorRsp(int code)118 void ServiceController::WriteErrorRsp(int code)
119 {
120 MsgHeader header = {MSG_VER, static_cast<uint8_t>(IoctlCmd::RSP_ERROR), code, 0};
121 (void)m_communicationSocket->Write(reinterpret_cast<char*>(&header), sizeof(MsgHeader));
122 return;
123 }
124
WriteQueryResponse(OptCRef<HilogData> pData)125 int ServiceController::WriteQueryResponse(OptCRef<HilogData> pData)
126 {
127 OutputRsp rsp;
128 if (pData == std::nullopt) {
129 rsp.end = true; // tell client it's the last messsage
130 return m_communicationSocket->Write(reinterpret_cast<char*>(&rsp), sizeof(rsp));
131 }
132 const HilogData& data = pData->get();
133 rsp.len = data.len; /* data len, equals tag_len plus content length, include '\0' */
134 rsp.level = data.level;
135 rsp.type = data.type;
136 rsp.tagLen = data.tag_len; /* include '\0' */
137 rsp.pid = data.pid;
138 rsp.tid = data.tid;
139 rsp.domain = data.domain;
140 rsp.tv_sec = data.tv_sec;
141 rsp.tv_nsec = data.tv_nsec;
142 rsp.mono_sec = data.mono_sec;
143 rsp.end = false;
144 static const int vec_num = 2;
145 iovec vec[vec_num];
146 vec[0].iov_base = &rsp;
147 vec[0].iov_len = sizeof(OutputRsp);
148 vec[1].iov_base = data.tag;
149 vec[1].iov_len = data.len;
150 return m_communicationSocket->WriteV(vec, vec_num);
151 }
152
StatsEntry2StatsRsp(const StatsEntry & entry,StatsRsp & rsp)153 static void StatsEntry2StatsRsp(const StatsEntry &entry, StatsRsp &rsp)
154 {
155 // can't use std::copy, because StatsRsp is a packet struct
156 int i = 0;
157 for (i = 0; i < LevelNum; i++) {
158 rsp.lines[i] = entry.lines[i];
159 rsp.len[i] = entry.len[i];
160 }
161 rsp.dropped = entry.dropped;
162 rsp.freqMax = entry.GetFreqMax();
163 rsp.freqMaxSec = entry.realTimeFreqMax.tv_sec;
164 rsp.freqMaxNsec = entry.realTimeFreqMax.tv_nsec;
165 rsp.throughputMax = entry.GetThroughputMax();
166 rsp.tpMaxSec = entry.realTimeThroughputMax.tv_sec;
167 rsp.tpMaxNsec = entry.realTimeThroughputMax.tv_nsec;
168 }
169
SendOverallStats(const LogStats & stats)170 void ServiceController::SendOverallStats(const LogStats& stats)
171 {
172 StatsQueryRsp rsp;
173 const LogTypeDomainTable& ldTable = stats.GetDomainTable();
174 const PidTable& pTable = stats.GetPidTable();
175 const LogTimeStamp tsBegin = stats.GetBeginTs();
176 rsp.tsBeginSec = tsBegin.tv_sec;
177 rsp.tsBeginNsec = tsBegin.tv_nsec;
178 const LogTimeStamp monoBegin = stats.GetBeginMono();
179 LogTimeStamp monoNow(CLOCK_MONOTONIC);
180 monoNow -= monoBegin;
181 rsp.durationSec = monoNow.tv_sec;
182 rsp.durationNsec = monoNow.tv_nsec;
183 stats.GetTotalLines(rsp.totalLines);
184 stats.GetTotalLens(rsp.totalLens);
185 rsp.typeNum = 0;
186 for (const DomainTable &dt : ldTable) {
187 if (dt.size() == 0) {
188 continue;
189 }
190 rsp.typeNum++;
191 }
192 rsp.ldStats = nullptr;
193 rsp.procNum = pTable.size();
194 rsp.pStats = nullptr;
195 m_communicationSocket->Write(reinterpret_cast<char *>(&rsp), sizeof(StatsQueryRsp));
196 }
197
SendLogTypeDomainStats(const LogStats & stats)198 void ServiceController::SendLogTypeDomainStats(const LogStats& stats)
199 {
200 const LogTypeDomainTable& ldTable = stats.GetDomainTable();
201 int typeNum = 0;
202 for (const DomainTable &dt : ldTable) {
203 if (dt.size() == 0) {
204 continue;
205 }
206 typeNum++;
207 }
208 int msgSize = typeNum * sizeof(LogTypeDomainStatsRsp);
209 if (msgSize == 0) {
210 return;
211 }
212 char* tmp = new (std::nothrow) char[msgSize];
213 if (tmp == nullptr) {
214 return;
215 }
216 if (memset_s(tmp, msgSize, 0, msgSize) != 0) {
217 delete []tmp;
218 tmp = nullptr;
219 return;
220 }
221 LogTypeDomainStatsRsp *ldStats = reinterpret_cast<LogTypeDomainStatsRsp *>(tmp);
222 int i = 0;
223 int j = 0;
224 for (const DomainTable &dt : ldTable) {
225 j++;
226 if (dt.size() == 0) {
227 continue;
228 }
229 ldStats[i].type = (j - 1);
230 ldStats[i].domainNum = dt.size();
231 i++;
232 }
233 m_communicationSocket->Write(tmp, msgSize);
234 delete []tmp;
235 tmp = nullptr;
236 }
237
SendDomainStats(const LogStats & stats)238 void ServiceController::SendDomainStats(const LogStats& stats)
239 {
240 const LogTypeDomainTable& ldTable = stats.GetDomainTable();
241 for (const DomainTable &dt : ldTable) {
242 if (dt.size() == 0) {
243 continue;
244 }
245 int msgSize = dt.size() * sizeof(DomainStatsRsp);
246 char *tmp = new (std::nothrow) char[msgSize];
247 if (tmp == nullptr) {
248 return;
249 }
250 if (memset_s(tmp, msgSize, 0, msgSize) != 0) {
251 delete []tmp;
252 tmp = nullptr;
253 return;
254 }
255 DomainStatsRsp *dStats = reinterpret_cast<DomainStatsRsp *>(tmp);
256 int i = 0;
257 for (auto &it : dt) {
258 dStats[i].domain = it.first;
259 if (!stats.IsTagEnable()) {
260 dStats[i].tagNum = 0;
261 } else {
262 dStats[i].tagNum = it.second.tagStats.size();
263 }
264 if (dStats[i].tagNum == 0) {
265 dStats[i].tStats = nullptr;
266 }
267 StatsEntry2StatsRsp(it.second.stats, dStats[i].stats);
268 i++;
269 }
270 m_communicationSocket->Write(tmp, msgSize);
271 delete []tmp;
272 tmp = nullptr;
273 }
274 }
275
SendDomainTagStats(const LogStats & stats)276 void ServiceController::SendDomainTagStats(const LogStats& stats)
277 {
278 const LogTypeDomainTable& ldTable = stats.GetDomainTable();
279 for (const DomainTable &dt : ldTable) {
280 if (dt.size() == 0) {
281 continue;
282 }
283 for (auto &it : dt) {
284 SendTagStats(it.second.tagStats);
285 }
286 }
287 }
288
SendProcStats(const LogStats & stats)289 void ServiceController::SendProcStats(const LogStats& stats)
290 {
291 const PidTable& pTable = stats.GetPidTable();
292 int msgSize = pTable.size() * sizeof(ProcStatsRsp);
293 if (msgSize == 0) {
294 return;
295 }
296 char* tmp = new (std::nothrow) char[msgSize];
297 if (tmp == nullptr) {
298 return;
299 }
300 if (memset_s(tmp, msgSize, 0, msgSize) != 0) {
301 delete []tmp;
302 tmp = nullptr;
303 return;
304 }
305 ProcStatsRsp *pStats = reinterpret_cast<ProcStatsRsp *>(tmp);
306 int i = 0;
307 for (auto &it : pTable) {
308 ProcStatsRsp &procStats = pStats[i];
309 i++;
310 procStats.pid = it.first;
311 if (strncpy_s(procStats.name, MAX_PROC_NAME_LEN, it.second.name.c_str(), MAX_PROC_NAME_LEN - 1) != 0) {
312 continue;
313 }
314 StatsEntry2StatsRsp(it.second.statsAll, procStats.stats);
315 procStats.typeNum = 0;
316 for (auto &itt : it.second.stats) {
317 if (itt.GetTotalLines() == 0) {
318 continue;
319 }
320 procStats.typeNum++;
321 }
322 if (!stats.IsTagEnable()) {
323 procStats.tagNum = 0;
324 } else {
325 procStats.tagNum = it.second.tagStats.size();
326 }
327 if (procStats.tagNum == 0) {
328 procStats.tStats = nullptr;
329 }
330 }
331 m_communicationSocket->Write(tmp, msgSize);
332 delete []tmp;
333 tmp = nullptr;
334 }
335
SendProcLogTypeStats(const LogStats & stats)336 void ServiceController::SendProcLogTypeStats(const LogStats& stats)
337 {
338 const PidTable& pTable = stats.GetPidTable();
339 for (auto &it : pTable) {
340 int typeNum = 0;
341 for (auto &itt : it.second.stats) {
342 if (itt.GetTotalLines() == 0) {
343 continue;
344 }
345 typeNum++;
346 }
347 int msgSize = typeNum * sizeof(LogTypeStatsRsp);
348 if (msgSize == 0) {
349 return;
350 }
351 char* tmp = new (std::nothrow) char[msgSize];
352 if (tmp == nullptr) {
353 return;
354 }
355 if (memset_s(tmp, msgSize, 0, msgSize) != 0) {
356 delete []tmp;
357 tmp = nullptr;
358 return;
359 }
360 LogTypeStatsRsp *lStats = reinterpret_cast<LogTypeStatsRsp *>(tmp);
361 int i = 0;
362 int j = 0;
363 for (auto &itt : it.second.stats) {
364 j++;
365 if (itt.GetTotalLines() == 0) {
366 continue;
367 }
368 LogTypeStatsRsp &logTypeStats = lStats[i];
369 logTypeStats.type = (j - 1);
370 StatsEntry2StatsRsp(itt, logTypeStats.stats);
371 i++;
372 }
373 m_communicationSocket->Write(tmp, msgSize);
374 delete []tmp;
375 tmp = nullptr;
376 }
377 }
378
SendProcTagStats(const LogStats & stats)379 void ServiceController::SendProcTagStats(const LogStats& stats)
380 {
381 const PidTable& pTable = stats.GetPidTable();
382 for (auto &it : pTable) {
383 SendTagStats(it.second.tagStats);
384 }
385 }
386
SendTagStats(const TagTable & tagTable)387 void ServiceController::SendTagStats(const TagTable &tagTable)
388 {
389 int msgSize = tagTable.size() * sizeof(TagStatsRsp);
390 if (msgSize == 0) {
391 return;
392 }
393 char* tmp = new (std::nothrow) char[msgSize];
394 if (tmp == nullptr) {
395 return;
396 }
397 if (memset_s(tmp, msgSize, 0, msgSize) != 0) {
398 delete []tmp;
399 tmp = nullptr;
400 return;
401 }
402 TagStatsRsp *tStats = reinterpret_cast<TagStatsRsp *>(tmp);
403 int i = 0;
404 for (auto &itt : tagTable) {
405 TagStatsRsp &tagStats = tStats[i];
406 if (strncpy_s(tagStats.tag, MAX_TAG_LEN, itt.first.c_str(), MAX_TAG_LEN - 1) != 0) {
407 continue;
408 }
409 i++;
410 StatsEntry2StatsRsp(itt.second, tagStats.stats);
411 }
412 m_communicationSocket->Write(tmp, msgSize);
413 delete []tmp;
414 tmp = nullptr;
415 }
416
CheckOutputRqst(const OutputRqst & rqst)417 int ServiceController::CheckOutputRqst(const OutputRqst& rqst)
418 {
419 if (((rqst.types & (0b01 << LOG_KMSG)) != 0) && (GetBitsCount(rqst.types) > 1)) {
420 return ERR_QUERY_TYPE_INVALID;
421 }
422 if (rqst.domainCount > MAX_DOMAINS) {
423 return ERR_TOO_MANY_DOMAINS;
424 }
425 if (rqst.tagCount > MAX_TAGS) {
426 return ERR_TOO_MANY_TAGS;
427 }
428 if (rqst.pidCount > MAX_PIDS) {
429 return ERR_TOO_MANY_PIDS;
430 }
431 // Check Uid permission
432 uid_t uid = m_communicationSocket->GetUid();
433 if (uid != ROOT_UID && uid != SHELL_UID && rqst.pidCount > 0) {
434 return ERR_NO_PID_PERMISSION;
435 }
436 return RET_SUCCESS;
437 }
438
LogFilterFromOutputRqst(const OutputRqst & rqst,LogFilter & filter)439 void ServiceController::LogFilterFromOutputRqst(const OutputRqst& rqst, LogFilter& filter)
440 {
441 if (rqst.types == 0) {
442 filter.types = DEFAULT_LOG_TYPES;
443 } else {
444 filter.types = rqst.types;
445 }
446 if (rqst.levels == 0) {
447 filter.levels = ~rqst.levels; // 0 means all
448 } else {
449 filter.levels = rqst.levels;
450 }
451 int i;
452 filter.blackDomain = rqst.blackDomain;
453 filter.domainCount = rqst.domainCount;
454 for (i = 0; i < rqst.domainCount; i++) {
455 filter.domains[i] = rqst.domains[i];
456 }
457 filter.blackTag = rqst.blackTag;
458 filter.tagCount = rqst.tagCount;
459 for (i = 0; i < rqst.tagCount; i++) {
460 (void)strncpy_s(filter.tags[i], MAX_TAG_LEN, rqst.tags[i], MAX_TAG_LEN - 1);
461 }
462 filter.blackPid = rqst.blackPid;
463 filter.pidCount = rqst.pidCount;
464 for (i = 0; i < rqst.pidCount; i++) {
465 filter.pids[i] = rqst.pids[i];
466 }
467 (void)strncpy_s(filter.regex, MAX_REGEX_STR_LEN, rqst.regex, MAX_REGEX_STR_LEN - 1);
468 filter.Print();
469 // Permission check
470 uid_t uid = m_communicationSocket->GetUid();
471 uint32_t pid = static_cast<uint32_t>(m_communicationSocket->GetPid());
472 if (uid != ROOT_UID && uid != SHELL_UID) {
473 filter.blackPid = false;
474 filter.pidCount = 1;
475 filter.pids[0] = pid;
476 uint32_t ppid = GetPPidByPid(pid);
477 if (ppid > 0) {
478 filter.pidCount++;
479 filter.pids[1] = ppid;
480 }
481 }
482 }
483
HandleOutputRqst(const OutputRqst & rqst)484 void ServiceController::HandleOutputRqst(const OutputRqst &rqst)
485 {
486 // check OutputRqst
487 int ret = CheckOutputRqst(rqst);
488 if (ret != RET_SUCCESS) {
489 WriteErrorRsp(ret);
490 return;
491 }
492 LogFilter filter = {0};
493 LogFilterFromOutputRqst(rqst, filter);
494 int lines = rqst.headLines ? rqst.headLines : rqst.tailLines;
495 int tailCount = rqst.tailLines;
496 int linesCountDown = lines;
497
498 WriteRspHeader(IoctlCmd::OUTPUT_RSP, sizeof(OutputRsp));
499 for (;;) {
500 std::optional<HilogData> data = m_hilogBuffer.Query(filter, m_bufReader, tailCount);
501 if (!data.has_value()) {
502 if (rqst.noBlock) {
503 // reach the end of buffer and don't block
504 (void)WriteQueryResponse(std::nullopt);
505 break;
506 }
507 std::unique_lock<decltype(m_notifyNewDataMtx)> ul(m_notifyNewDataMtx);
508 m_notifyNewDataCv.wait(ul);
509 continue;
510 }
511 int ret = WriteQueryResponse(data.value());
512 if (ret < 0) { // write socket failed, it means that client has disconnected
513 std::cerr << "Client disconnect" << std::endl;
514 break;
515 }
516 if (lines && (--linesCountDown) <= 0) {
517 (void)WriteQueryResponse(std::nullopt);
518 sleep(1); // let client receive all messages and exit gracefully
519 break;
520 }
521 }
522 }
523
CheckPersistStartRqst(const PersistStartRqst & rqst)524 int ServiceController::CheckPersistStartRqst(const PersistStartRqst &rqst)
525 {
526 // check OutputFilter
527 int ret = CheckOutputRqst(rqst.outputFilter);
528 if (ret != RET_SUCCESS) {
529 return ret;
530 }
531 if (rqst.jobId && (rqst.jobId < JOB_ID_MIN || rqst.jobId == JOB_ID_MAX)) {
532 return ERR_LOG_PERSIST_JOBID_INVALID;
533 }
534 if (rqst.fileSize && (rqst.fileSize < MIN_LOG_FILE_SIZE || rqst.fileSize > MAX_LOG_FILE_SIZE)) {
535 return ERR_LOG_PERSIST_FILE_SIZE_INVALID;
536 }
537 if (rqst.fileName[0] && IsValidFileName(rqst.fileName) == false) {
538 return ERR_LOG_PERSIST_FILE_NAME_INVALID;
539 }
540 if (rqst.fileNum && (rqst.fileNum > MAX_LOG_FILE_NUM || rqst.fileNum < MIN_LOG_FILE_NUM)) {
541 return ERR_LOG_FILE_NUM_INVALID;
542 }
543 return RET_SUCCESS;
544 }
545
PersistStartRqst2Msg(const PersistStartRqst & rqst,LogPersistStartMsg & msg)546 void ServiceController::PersistStartRqst2Msg(const PersistStartRqst &rqst, LogPersistStartMsg &msg)
547 {
548 LogFilterFromOutputRqst(rqst.outputFilter, msg.filter);
549 bool isKmsgType = rqst.outputFilter.types == (0b01 << LOG_KMSG);
550 msg.compressAlg = LogCompress::Str2CompressType(rqst.stream);
551 msg.fileSize = rqst.fileSize == 0 ? DEFAULT_PERSIST_FILE_SIZE : rqst.fileSize;
552 msg.fileNum = rqst.fileNum == 0 ? DEFAULT_PERSIST_FILE_NUM : rqst.fileNum;
553 msg.jobId = rqst.jobId;
554 if (msg.jobId == 0) {
555 msg.jobId = isKmsgType ? DEFAULT_PERSIST_KMSG_JOB_ID : DEFAULT_PERSIST_NORMAL_JOB_ID;
556 }
557 string fileName = rqst.fileName;
558 if (fileName == "") {
559 fileName = (isKmsgType ? "hilog_kmsg" : "hilog");
560 }
561 string filePath = LOG_PERSISTER_DIR + fileName;
562 (void)strncpy_s(msg.filePath, FILE_PATH_MAX_LEN, filePath.c_str(), filePath.length());
563 }
564
StartPersistStoreJob(const PersistRecoveryInfo & info,HilogBuffer & hilogBuffer,bool restore)565 int StartPersistStoreJob(const PersistRecoveryInfo& info, HilogBuffer& hilogBuffer, bool restore)
566 {
567 std::shared_ptr<LogPersister> persister = LogPersister::CreateLogPersister(hilogBuffer);
568 if (persister == nullptr) {
569 return RET_FAIL;
570 }
571 int ret = persister->Init(info, restore);
572 if (ret != RET_SUCCESS) {
573 return ret;
574 }
575 persister->Start();
576 return RET_SUCCESS;
577 }
578
HandlePersistStartRqst(const PersistStartRqst & rqst)579 void ServiceController::HandlePersistStartRqst(const PersistStartRqst &rqst)
580 {
581 int ret = WaitingToDo(WAITING_DATA_MS, HILOG_FILE_DIR, [](const string &path) {
582 struct stat s;
583 if (stat(path.c_str(), &s) != -1) {
584 return RET_SUCCESS;
585 }
586 return RET_FAIL;
587 });
588 if (ret != RET_SUCCESS) {
589 WriteErrorRsp(ERR_LOG_PERSIST_FILE_PATH_INVALID);
590 return;
591 }
592 ret = CheckPersistStartRqst(rqst);
593 if (ret != RET_SUCCESS) {
594 WriteErrorRsp(ret);
595 return;
596 }
597 list<LogPersistQueryResult> resultList;
598 LogPersister::Query(resultList);
599 if (resultList.size() >= MAX_JOBS) {
600 WriteErrorRsp(ERR_TOO_MANY_JOBS);
601 return;
602 }
603 LogPersistStartMsg msg = { 0 };
604 PersistStartRqst2Msg(rqst, msg);
605 PersistRecoveryInfo info = {0, msg};
606 ret = StartPersistStoreJob(info, m_hilogBuffer, false);
607 if (ret != RET_SUCCESS) {
608 WriteErrorRsp(ret);
609 return;
610 }
611 PersistStartRsp rsp = { msg.jobId };
612 WriteRspHeader(IoctlCmd::PERSIST_START_RSP, sizeof(rsp));
613 (void)m_communicationSocket->Write(reinterpret_cast<char*>(&rsp), sizeof(rsp));
614 }
615
HandlePersistStopRqst(const PersistStopRqst & rqst)616 void ServiceController::HandlePersistStopRqst(const PersistStopRqst &rqst)
617 {
618 PersistStopRsp rsp = { 0 };
619 list<LogPersistQueryResult> resultList;
620 LogPersister::Query(resultList);
621 if (rqst.jobId == 0 && resultList.empty()) {
622 WriteErrorRsp(ERR_PERSIST_TASK_EMPTY);
623 return;
624 }
625 for (auto it = resultList.begin(); it != resultList.end() && rsp.jobNum < MAX_JOBS; ++it) {
626 uint32_t jobId = it->jobId;
627 if (rqst.jobId == 0 || rqst.jobId == jobId) {
628 (void)LogPersister::Kill(jobId);
629 rsp.jobId[rsp.jobNum] = jobId;
630 rsp.jobNum++;
631 }
632 }
633 if (rsp.jobNum == 0) {
634 WriteErrorRsp(ERR_JOBID_NOT_EXSIST);
635 return;
636 }
637 WriteRspHeader(IoctlCmd::PERSIST_STOP_RSP, sizeof(rsp));
638 (void)m_communicationSocket->Write(reinterpret_cast<char*>(&rsp), sizeof(rsp));
639 }
640
HandlePersistQueryRqst(const PersistQueryRqst & rqst)641 void ServiceController::HandlePersistQueryRqst(const PersistQueryRqst& rqst)
642 {
643 list<LogPersistQueryResult> resultList;
644 LogPersister::Query(resultList);
645 if (resultList.size() == 0) {
646 WriteErrorRsp(ERR_NO_RUNNING_TASK);
647 return;
648 }
649 PersistQueryRsp rsp = { 0 };
650 for (auto it = resultList.begin(); it != resultList.end() && rsp.jobNum < MAX_JOBS; ++it) {
651 PersistTaskInfo &task = rsp.taskInfo[rsp.jobNum];
652 task.jobId = it->jobId;
653 task.fileNum = it->fileNum;
654 task.fileSize = it->fileSize;
655 task.outputFilter.types = it->logType;
656 (void)strncpy_s(task.fileName, MAX_FILE_NAME_LEN, it->filePath, MAX_FILE_NAME_LEN - 1);
657 (void)strncpy_s(task.stream, MAX_STREAM_NAME_LEN,
658 LogCompress::CompressType2Str(it->compressAlg).c_str(), MAX_STREAM_NAME_LEN - 1);
659 rsp.jobNum++;
660 }
661 WriteRspHeader(IoctlCmd::PERSIST_QUERY_RSP, sizeof(rsp));
662 (void)m_communicationSocket->Write(reinterpret_cast<char*>(&rsp), sizeof(rsp));
663 }
664
HandleBufferSizeGetRqst(const BufferSizeGetRqst & rqst)665 void ServiceController::HandleBufferSizeGetRqst(const BufferSizeGetRqst& rqst)
666 {
667 vector<uint16_t> allTypes = GetAllLogTypes();
668 uint16_t types = rqst.types;
669 if (types == 0) {
670 types = DEFAULT_LOG_TYPES;
671 }
672 int i = 0;
673 BufferSizeGetRsp rsp = { 0 };
674 for (uint16_t t : allTypes) {
675 if ((1 << t) & types) {
676 rsp.size[t] = static_cast<uint32_t>(m_hilogBuffer.GetBuffLen(t));
677 i++;
678 }
679 }
680 if (i == 0) {
681 WriteErrorRsp(ERR_LOG_TYPE_INVALID);
682 return;
683 }
684 WriteRspHeader(IoctlCmd::BUFFERSIZE_GET_RSP, sizeof(rsp));
685 (void)m_communicationSocket->Write(reinterpret_cast<char*>(&rsp), sizeof(rsp));
686 }
687
HandleBufferSizeSetRqst(const BufferSizeSetRqst & rqst)688 void ServiceController::HandleBufferSizeSetRqst(const BufferSizeSetRqst& rqst)
689 {
690 vector<uint16_t> allTypes = GetAllLogTypes();
691 uint16_t types = rqst.types;
692 if (types == 0) {
693 types = DEFAULT_LOG_TYPES;
694 }
695 int i = 0;
696 BufferSizeSetRsp rsp = { 0 };
697 for (uint16_t t : allTypes) {
698 if ((1 << t) & types) {
699 int ret = m_hilogBuffer.SetBuffLen(t, rqst.size);
700 if (ret != RET_SUCCESS) {
701 rsp.size[t] = ret;
702 } else {
703 SetBufferSize(t, true, rqst.size);
704 rsp.size[t] = rqst.size;
705 }
706 i++;
707 }
708 }
709 if (i == 0) {
710 WriteErrorRsp(ERR_LOG_TYPE_INVALID);
711 return;
712 }
713 WriteRspHeader(IoctlCmd::BUFFERSIZE_SET_RSP, sizeof(rsp));
714 (void)m_communicationSocket->Write(reinterpret_cast<char*>(&rsp), sizeof(rsp));
715 }
716
HandleStatsQueryRqst(const StatsQueryRqst & rqst)717 void ServiceController::HandleStatsQueryRqst(const StatsQueryRqst& rqst)
718 {
719 LogStats& stats = m_hilogBuffer.GetStatsInfo();
720 if (!stats.IsEnable()) {
721 WriteErrorRsp(ERR_STATS_NOT_ENABLE);
722 return;
723 }
724 std::unique_lock<std::mutex> lk(stats.GetLock());
725
726 WriteRspHeader(IoctlCmd::STATS_QUERY_RSP, sizeof(StatsQueryRsp));
727 SendOverallStats(stats);
728 SendLogTypeDomainStats(stats);
729 SendDomainStats(stats);
730 if (stats.IsTagEnable()) {
731 SendDomainTagStats(stats);
732 }
733 SendProcStats(stats);
734 SendProcLogTypeStats(stats);
735 if (stats.IsTagEnable()) {
736 SendProcTagStats(stats);
737 }
738 }
739
HandleStatsClearRqst(const StatsClearRqst & rqst)740 void ServiceController::HandleStatsClearRqst(const StatsClearRqst& rqst)
741 {
742 m_hilogBuffer.ResetStats();
743 StatsClearRsp rsp = { 0 };
744 WriteRspHeader(IoctlCmd::STATS_CLEAR_RSP, sizeof(rsp));
745 (void)m_communicationSocket->Write(reinterpret_cast<char*>(&rsp), sizeof(rsp));
746 }
747
HandleDomainFlowCtrlRqst(const DomainFlowCtrlRqst & rqst)748 void ServiceController::HandleDomainFlowCtrlRqst(const DomainFlowCtrlRqst& rqst)
749 {
750 SetDomainSwitchOn(rqst.on);
751 m_logCollector.SetLogFlowControl(rqst.on);
752 // set domain flow control later
753 DomainFlowCtrlRsp rsp = { 0 };
754 WriteRspHeader(IoctlCmd::DOMAIN_FLOWCTRL_RSP, sizeof(rsp));
755 (void)m_communicationSocket->Write(reinterpret_cast<char*>(&rsp), sizeof(rsp));
756 }
757
HandleLogRemoveRqst(const LogRemoveRqst & rqst)758 void ServiceController::HandleLogRemoveRqst(const LogRemoveRqst& rqst)
759 {
760 vector<uint16_t> allTypes = GetAllLogTypes();
761 uint16_t types = rqst.types;
762 if (types == 0) {
763 types = DEFAULT_REMOVE_LOG_TYPES;
764 }
765 int i = 0;
766 LogRemoveRsp rsp = { types };
767 for (uint16_t t : allTypes) {
768 if ((1 << t) & types) {
769 (void)m_hilogBuffer.Delete(t);
770 i++;
771 }
772 }
773 if (i == 0) {
774 WriteErrorRsp(ERR_LOG_TYPE_INVALID);
775 return;
776 }
777 WriteRspHeader(IoctlCmd::LOG_REMOVE_RSP, sizeof(rsp));
778 (void)m_communicationSocket->Write(reinterpret_cast<char*>(&rsp), sizeof(rsp));
779 }
780
HandleLogKmsgEnableRqst(const KmsgEnableRqst & rqst)781 void ServiceController::HandleLogKmsgEnableRqst(const KmsgEnableRqst& rqst)
782 {
783 SetKmsgSwitchOn(rqst.on);
784
785 LogKmsg& logKmsg = LogKmsg::GetInstance(m_hilogBuffer);
786 if (rqst.on) {
787 logKmsg.Start();
788 } else {
789 logKmsg.Stop();
790 }
791 // set domain flow control later
792 KmsgEnableRsp rsp = { 0 };
793 WriteRspHeader(IoctlCmd::KMSG_ENABLE_RSP, sizeof(rsp));
794 (void)m_communicationSocket->Write(reinterpret_cast<char*>(&rsp), sizeof(rsp));
795 }
796
IsValidCmd(const CmdList & list,IoctlCmd cmd)797 bool ServiceController::IsValidCmd(const CmdList& list, IoctlCmd cmd)
798 {
799 auto it = find(list.begin(), list.end(), cmd);
800 return (it != list.end());
801 }
802
CommunicationLoop(std::atomic<bool> & stopLoop,const CmdList & list)803 void ServiceController::CommunicationLoop(std::atomic<bool>& stopLoop, const CmdList& list)
804 {
805 std::cout << "ServiceController Loop Begin" << std::endl;
806 MsgHeader hdr;
807 int ret = GetMsgHeader(hdr);
808 if (ret != RET_SUCCESS) {
809 return;
810 }
811 IoctlCmd cmd = static_cast<IoctlCmd>(hdr.cmd);
812 std::cout << "Receive cmd: " << static_cast<int>(cmd) << endl;
813 if (!IsValidCmd(list, cmd)) {
814 cout << "Not valid cmd for this executor" << endl;
815 WriteErrorRsp(ERR_INVALID_RQST_CMD);
816 return;
817 }
818 switch (cmd) {
819 case IoctlCmd::OUTPUT_RQST: {
820 RequestHandler<OutputRqst>(hdr, [this](const OutputRqst& rqst) {
821 HandleOutputRqst(rqst);
822 });
823 break;
824 }
825 case IoctlCmd::PERSIST_START_RQST: {
826 RequestHandler<PersistStartRqst>(hdr, [this](const PersistStartRqst& rqst) {
827 HandlePersistStartRqst(rqst);
828 });
829 break;
830 }
831 case IoctlCmd::PERSIST_STOP_RQST: {
832 RequestHandler<PersistStopRqst>(hdr, [this](const PersistStopRqst& rqst) {
833 HandlePersistStopRqst(rqst);
834 });
835 break;
836 }
837 case IoctlCmd::PERSIST_QUERY_RQST: {
838 RequestHandler<PersistQueryRqst>(hdr, [this](const PersistQueryRqst& rqst) {
839 HandlePersistQueryRqst(rqst);
840 });
841 break;
842 }
843 case IoctlCmd::BUFFERSIZE_GET_RQST: {
844 RequestHandler<BufferSizeGetRqst>(hdr, [this](const BufferSizeGetRqst& rqst) {
845 HandleBufferSizeGetRqst(rqst);
846 });
847 break;
848 }
849 case IoctlCmd::BUFFERSIZE_SET_RQST: {
850 RequestHandler<BufferSizeSetRqst>(hdr, [this](const BufferSizeSetRqst& rqst) {
851 HandleBufferSizeSetRqst(rqst);
852 });
853 break;
854 }
855 case IoctlCmd::STATS_QUERY_RQST: {
856 RequestHandler<StatsQueryRqst>(hdr, [this](const StatsQueryRqst& rqst) {
857 HandleStatsQueryRqst(rqst);
858 });
859 break;
860 }
861 case IoctlCmd::STATS_CLEAR_RQST: {
862 RequestHandler<StatsClearRqst>(hdr, [this](const StatsClearRqst& rqst) {
863 HandleStatsClearRqst(rqst);
864 });
865 break;
866 }
867 case IoctlCmd::DOMAIN_FLOWCTRL_RQST: {
868 RequestHandler<DomainFlowCtrlRqst>(hdr, [this](const DomainFlowCtrlRqst& rqst) {
869 HandleDomainFlowCtrlRqst(rqst);
870 });
871 break;
872 }
873 case IoctlCmd::LOG_REMOVE_RQST: {
874 RequestHandler<LogRemoveRqst>(hdr, [this](const LogRemoveRqst& rqst) {
875 HandleLogRemoveRqst(rqst);
876 });
877 break;
878 }
879 case IoctlCmd::KMSG_ENABLE_RQST: {
880 RequestHandler<KmsgEnableRqst>(hdr, [this](const KmsgEnableRqst& rqst) {
881 HandleLogKmsgEnableRqst(rqst);
882 });
883 break;
884 }
885 default: {
886 std::cerr << " Unknown message. Skipped!" << endl;
887 break;
888 }
889 }
890 stopLoop.store(true);
891 std::cout << " ServiceController Loop End" << endl;
892 }
893
NotifyForNewData()894 void ServiceController::NotifyForNewData()
895 {
896 m_notifyNewDataCv.notify_one();
897 }
898
RestorePersistJobs(HilogBuffer & hilogBuffer)899 int RestorePersistJobs(HilogBuffer& hilogBuffer)
900 {
901 std::cout << " Start restoring persist jobs!\n";
902 DIR *dir = opendir(LOG_PERSISTER_DIR.c_str());
903 struct dirent *ent = nullptr;
904 if (dir == nullptr) {
905 perror("Failed to open persister directory!");
906 return ERR_LOG_PERSIST_DIR_OPEN_FAIL;
907 }
908 while ((ent = readdir(dir)) != nullptr) {
909 size_t length = strlen(ent->d_name);
910 std::string pPath(ent->d_name, length);
911 if (length >= INFO_SUFFIX && pPath.substr(length - INFO_SUFFIX, length) == ".info") {
912 if (pPath == "hilog.info") {
913 continue;
914 }
915 std::cout << " Found a persist job! Path: " << LOG_PERSISTER_DIR + pPath << "\n";
916 FILE* infile = fopen((LOG_PERSISTER_DIR + pPath).c_str(), "r");
917 if (infile == nullptr) {
918 std::cerr << " Error opening recovery info file!\n";
919 continue;
920 }
921 PersistRecoveryInfo info = { 0 };
922 fread(&info, sizeof(PersistRecoveryInfo), 1, infile);
923 uint64_t hashSum = 0L;
924 fread(&hashSum, sizeof(hashSum), 1, infile);
925 fclose(infile);
926 uint64_t hash = GenerateHash(reinterpret_cast<char *>(&info), sizeof(PersistRecoveryInfo));
927 if (hash != hashSum) {
928 std::cout << " Info file checksum Failed!\n";
929 continue;
930 }
931 int result = StartPersistStoreJob(info, hilogBuffer, true);
932 std::cout << " Recovery Info:\n"
933 << " restoring result: " << (result == RET_SUCCESS
934 ? std::string("Success\n")
935 : std::string("Failed(") + std::to_string(result) + ")\n")
936 << " jobId=" << (unsigned)(info.msg.jobId) << "\n"
937 << " filePath=" << (info.msg.filePath) << "\n"
938 << " index=" << (info.index) << "\n";
939 }
940 }
941 closedir(dir);
942 std::cout << " Finished restoring persist jobs!\n";
943 return EXIT_SUCCESS;
944 }
945 } // namespace HiviewDFX
946 } // namespace OHOS
947