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