• 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 
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