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
16 #include "log_kmsg.h"
17 #include <cstdlib>
18 #include <cinttypes>
19 #include <iostream>
20 #include <string>
21 #include <thread>
22 #include <fstream>
23 #include <sys/klog.h>
24 #include <sys/syslog.h>
25 #include <unistd.h>
26 #include <fcntl.h>
27 #include <sys/types.h>
28 #include <sys/stat.h>
29 #include <sys/prctl.h>
30 #include <init_file.h>
31 #include <hilog/log.h>
32 #include <log_utils.h>
33
34 namespace OHOS {
35 namespace HiviewDFX {
36 using namespace std;
37
38 constexpr int OPEN_KMSG_TIME = 3000; // 3s
39 constexpr int RETRY_WAIT = 10; // 10us
40 const char* PROC_KMSG = "/proc/kmsg";
41 const char* DEV_KMSG = "/dev/kmsg";
42
GetInstance(HilogBuffer & hilogBuffer)43 LogKmsg& LogKmsg::GetInstance(HilogBuffer& hilogBuffer)
44 {
45 static LogKmsg logKmsg(hilogBuffer);
46 return logKmsg;
47 }
48
LinuxReadOneKmsg(KmsgParser & parser)49 ssize_t LogKmsg::LinuxReadOneKmsg(KmsgParser& parser)
50 {
51 std::vector<char> kmsgBuffer(BUFSIZ, '\0');
52 ssize_t size = -1;
53 do {
54 size = read(kmsgCtl, kmsgBuffer.data(), BUFSIZ - 1);
55 } while (size < 0 && errno == EPIPE);
56 if (size > 0) {
57 std::optional<HilogMsgWrapper> msgWrap = parser.ParseKmsg(kmsgBuffer);
58 if (msgWrap.has_value()) {
59 bool isFull = false;
60 hilogBuffer.Insert(msgWrap->GetHilogMsg(), isFull);
61 while (isFull) {
62 usleep(RETRY_WAIT);
63 hilogBuffer.Insert(msgWrap->GetHilogMsg(), isFull);
64 }
65 }
66 }
67 return size;
68 }
69
LinuxReadAllKmsg()70 int LogKmsg::LinuxReadAllKmsg()
71 {
72 ssize_t rdFailTimes = 0;
73 const ssize_t maxFailTime = 10;
74 if (access(PROC_KMSG, R_OK) != 0) {
75 this->kmsgCtl = GetControlFile(DEV_KMSG);
76 if (this->kmsgCtl < 0) {
77 return RET_FAIL;
78 }
79 } else {
80 int ret = WaitingToDo(OPEN_KMSG_TIME, PROC_KMSG, [this] (const string &path) {
81 this->kmsgCtl = open(path.c_str(), O_RDONLY);
82 if (this->kmsgCtl < 0) {
83 std::cout << "Cannot open kmsg " << this->kmsgCtl << std::endl;
84 return RET_FAIL;
85 }
86 return RET_SUCCESS;
87 });
88 if (ret != RET_SUCCESS) {
89 return RET_FAIL;
90 }
91 }
92
93 std::cout << "Open kmsg success." << std::endl;
94 std::unique_ptr<KmsgParser> parser = std::make_unique<KmsgParser>();
95 if (parser == nullptr) {
96 return -1;
97 }
98 while (true) {
99 if (threadStatus == STOP) {
100 break;
101 }
102 ssize_t sz = LinuxReadOneKmsg(*parser);
103 if (sz < 0) {
104 rdFailTimes++;
105 if (maxFailTime < rdFailTimes) {
106 std::cout << "Read kmsg failed more than maxFailTime" << std::endl;
107 return -1;
108 }
109 sleep(1);
110 continue;
111 }
112 rdFailTimes = 0;
113 }
114 return 1;
115 }
116
ReadAllKmsg()117 void LogKmsg::ReadAllKmsg()
118 {
119 prctl(PR_SET_NAME, "hilogd.rd_kmsg");
120 #ifdef __linux__
121 std::cout << "Platform: Linux" << std::endl;
122 LinuxReadAllKmsg();
123 #endif
124 }
125
Start()126 void LogKmsg::Start()
127 {
128 std::lock_guard<decltype(startMtx)> lock(startMtx);
129 if (threadStatus == NONEXIST || threadStatus == STOP) {
130 logKmsgThread = std::thread ([this]() {
131 ReadAllKmsg();
132 });
133 } else {
134 std::cout << " Thread already started!\n";
135 }
136 threadStatus = START;
137 }
138
Stop()139 void LogKmsg::Stop()
140 {
141 if (threadStatus == NONEXIST || threadStatus == STOP) {
142 std::cout << "Thread was exited or not started!\n";
143 return;
144 }
145 threadStatus = STOP;
146 if (logKmsgThread.joinable()) {
147 logKmsgThread.join();
148 }
149 }
150
~LogKmsg()151 LogKmsg::~LogKmsg()
152 {
153 close(kmsgCtl);
154 }
155 } // namespace HiviewDFX
156 } // namespace OHOS
157