12498b56bSopenharmony_ci/*
22498b56bSopenharmony_ci * Copyright (c) 2021 Huawei Device Co., Ltd.
32498b56bSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
42498b56bSopenharmony_ci * you may not use this file except in compliance with the License.
52498b56bSopenharmony_ci * You may obtain a copy of the License at
62498b56bSopenharmony_ci *
72498b56bSopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
82498b56bSopenharmony_ci *
92498b56bSopenharmony_ci * Unless required by applicable law or agreed to in writing, software
102498b56bSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
112498b56bSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
122498b56bSopenharmony_ci * See the License for the specific language governing permissions and
132498b56bSopenharmony_ci * limitations under the License.
142498b56bSopenharmony_ci */
152498b56bSopenharmony_ci
162498b56bSopenharmony_ci#include "log_kmsg.h"
172498b56bSopenharmony_ci#include <cstdlib>
182498b56bSopenharmony_ci#include <cinttypes>
192498b56bSopenharmony_ci#include <iostream>
202498b56bSopenharmony_ci#include <string>
212498b56bSopenharmony_ci#include <thread>
222498b56bSopenharmony_ci#include <fstream>
232498b56bSopenharmony_ci#include <sys/klog.h>
242498b56bSopenharmony_ci#include <sys/syslog.h>
252498b56bSopenharmony_ci#include <unistd.h>
262498b56bSopenharmony_ci#include <fcntl.h>
272498b56bSopenharmony_ci#include <sys/types.h>
282498b56bSopenharmony_ci#include <sys/stat.h>
292498b56bSopenharmony_ci#include <sys/prctl.h>
302498b56bSopenharmony_ci#include <init_file.h>
312498b56bSopenharmony_ci#include <hilog/log.h>
322498b56bSopenharmony_ci#include <log_utils.h>
332498b56bSopenharmony_ci
342498b56bSopenharmony_cinamespace OHOS {
352498b56bSopenharmony_cinamespace HiviewDFX {
362498b56bSopenharmony_ciusing namespace std;
372498b56bSopenharmony_ci
382498b56bSopenharmony_ciconstexpr int OPEN_KMSG_TIME = 3000; // 3s
392498b56bSopenharmony_ciconstexpr int RETRY_WAIT = 10; // 10us
402498b56bSopenharmony_ciconst char* PROC_KMSG = "/proc/kmsg";
412498b56bSopenharmony_ciconst char* DEV_KMSG = "/dev/kmsg";
422498b56bSopenharmony_ci
432498b56bSopenharmony_ciLogKmsg& LogKmsg::GetInstance(HilogBuffer& hilogBuffer)
442498b56bSopenharmony_ci{
452498b56bSopenharmony_ci    static LogKmsg logKmsg(hilogBuffer);
462498b56bSopenharmony_ci    return logKmsg;
472498b56bSopenharmony_ci}
482498b56bSopenharmony_ci
492498b56bSopenharmony_cissize_t LogKmsg::LinuxReadOneKmsg(KmsgParser& parser)
502498b56bSopenharmony_ci{
512498b56bSopenharmony_ci    std::vector<char> kmsgBuffer(BUFSIZ, '\0');
522498b56bSopenharmony_ci    ssize_t size = -1;
532498b56bSopenharmony_ci    do {
542498b56bSopenharmony_ci        size = read(kmsgCtl, kmsgBuffer.data(), BUFSIZ - 1);
552498b56bSopenharmony_ci    } while (size < 0 && errno == EPIPE);
562498b56bSopenharmony_ci    if (size > 0) {
572498b56bSopenharmony_ci        std::optional<HilogMsgWrapper> msgWrap = parser.ParseKmsg(kmsgBuffer);
582498b56bSopenharmony_ci        if (msgWrap.has_value()) {
592498b56bSopenharmony_ci            bool isFull = false;
602498b56bSopenharmony_ci            hilogBuffer.Insert(msgWrap->GetHilogMsg(), isFull);
612498b56bSopenharmony_ci            while (isFull) {
622498b56bSopenharmony_ci                usleep(RETRY_WAIT);
632498b56bSopenharmony_ci                hilogBuffer.Insert(msgWrap->GetHilogMsg(), isFull);
642498b56bSopenharmony_ci            }
652498b56bSopenharmony_ci        }
662498b56bSopenharmony_ci    }
672498b56bSopenharmony_ci    return size;
682498b56bSopenharmony_ci}
692498b56bSopenharmony_ci
702498b56bSopenharmony_ciint LogKmsg::LinuxReadAllKmsg()
712498b56bSopenharmony_ci{
722498b56bSopenharmony_ci    ssize_t rdFailTimes = 0;
732498b56bSopenharmony_ci    const ssize_t maxFailTime = 10;
742498b56bSopenharmony_ci    if (access(PROC_KMSG, R_OK) != 0) {
752498b56bSopenharmony_ci        this->kmsgCtl = GetControlFile(DEV_KMSG);
762498b56bSopenharmony_ci        if (this->kmsgCtl < 0) {
772498b56bSopenharmony_ci            return RET_FAIL;
782498b56bSopenharmony_ci        }
792498b56bSopenharmony_ci    } else {
802498b56bSopenharmony_ci        int ret = WaitingToDo(OPEN_KMSG_TIME, PROC_KMSG, [this] (const string &path) {
812498b56bSopenharmony_ci            this->kmsgCtl = open(path.c_str(), O_RDONLY);
822498b56bSopenharmony_ci            if (this->kmsgCtl < 0) {
832498b56bSopenharmony_ci                std::cout << "Cannot open kmsg " << this->kmsgCtl << std::endl;
842498b56bSopenharmony_ci                return RET_FAIL;
852498b56bSopenharmony_ci            }
862498b56bSopenharmony_ci            return RET_SUCCESS;
872498b56bSopenharmony_ci        });
882498b56bSopenharmony_ci        if (ret != RET_SUCCESS) {
892498b56bSopenharmony_ci            return RET_FAIL;
902498b56bSopenharmony_ci        }
912498b56bSopenharmony_ci    }
922498b56bSopenharmony_ci
932498b56bSopenharmony_ci    std::cout << "Open kmsg success." << std::endl;
942498b56bSopenharmony_ci    std::unique_ptr<KmsgParser> parser = std::make_unique<KmsgParser>();
952498b56bSopenharmony_ci    if (parser == nullptr) {
962498b56bSopenharmony_ci        return -1;
972498b56bSopenharmony_ci    }
982498b56bSopenharmony_ci    while (true) {
992498b56bSopenharmony_ci        if (threadStatus == STOP) {
1002498b56bSopenharmony_ci            break;
1012498b56bSopenharmony_ci        }
1022498b56bSopenharmony_ci        ssize_t sz = LinuxReadOneKmsg(*parser);
1032498b56bSopenharmony_ci        if (sz < 0) {
1042498b56bSopenharmony_ci            rdFailTimes++;
1052498b56bSopenharmony_ci            if (maxFailTime < rdFailTimes) {
1062498b56bSopenharmony_ci                std::cout << "Read kmsg failed more than maxFailTime" << std::endl;
1072498b56bSopenharmony_ci                return -1;
1082498b56bSopenharmony_ci            }
1092498b56bSopenharmony_ci            sleep(1);
1102498b56bSopenharmony_ci            continue;
1112498b56bSopenharmony_ci        }
1122498b56bSopenharmony_ci        rdFailTimes = 0;
1132498b56bSopenharmony_ci    }
1142498b56bSopenharmony_ci    return 1;
1152498b56bSopenharmony_ci}
1162498b56bSopenharmony_ci
1172498b56bSopenharmony_civoid LogKmsg::ReadAllKmsg()
1182498b56bSopenharmony_ci{
1192498b56bSopenharmony_ci    prctl(PR_SET_NAME, "hilogd.rd_kmsg");
1202498b56bSopenharmony_ci#ifdef __linux__
1212498b56bSopenharmony_ci    std::cout << "Platform: Linux" << std::endl;
1222498b56bSopenharmony_ci    LinuxReadAllKmsg();
1232498b56bSopenharmony_ci#endif
1242498b56bSopenharmony_ci}
1252498b56bSopenharmony_ci
1262498b56bSopenharmony_civoid LogKmsg::Start()
1272498b56bSopenharmony_ci{
1282498b56bSopenharmony_ci    std::lock_guard<decltype(startMtx)> lock(startMtx);
1292498b56bSopenharmony_ci    if (threadStatus == NONEXIST || threadStatus == STOP) {
1302498b56bSopenharmony_ci        logKmsgThread = std::thread ([this]() {
1312498b56bSopenharmony_ci            ReadAllKmsg();
1322498b56bSopenharmony_ci        });
1332498b56bSopenharmony_ci    } else {
1342498b56bSopenharmony_ci        std::cout << " Thread already started!\n";
1352498b56bSopenharmony_ci    }
1362498b56bSopenharmony_ci    threadStatus = START;
1372498b56bSopenharmony_ci}
1382498b56bSopenharmony_ci
1392498b56bSopenharmony_civoid LogKmsg::Stop()
1402498b56bSopenharmony_ci{
1412498b56bSopenharmony_ci    if (threadStatus == NONEXIST || threadStatus == STOP) {
1422498b56bSopenharmony_ci        std::cout << "Thread was exited or not started!\n";
1432498b56bSopenharmony_ci        return;
1442498b56bSopenharmony_ci    }
1452498b56bSopenharmony_ci    threadStatus = STOP;
1462498b56bSopenharmony_ci    if (logKmsgThread.joinable()) {
1472498b56bSopenharmony_ci        logKmsgThread.join();
1482498b56bSopenharmony_ci    }
1492498b56bSopenharmony_ci}
1502498b56bSopenharmony_ci
1512498b56bSopenharmony_ciLogKmsg::~LogKmsg()
1522498b56bSopenharmony_ci{
1532498b56bSopenharmony_ci    close(kmsgCtl);
1542498b56bSopenharmony_ci}
1552498b56bSopenharmony_ci} // namespace HiviewDFX
1562498b56bSopenharmony_ci} // namespace OHOS
157