106f6ba60Sopenharmony_ci/*
206f6ba60Sopenharmony_ci * Copyright (c) Huawei Technologies Co., Ltd. 2021. All rights reserved.
306f6ba60Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
406f6ba60Sopenharmony_ci * you may not use this file except in compliance with the License.
506f6ba60Sopenharmony_ci * You may obtain a copy of the License at
606f6ba60Sopenharmony_ci *
706f6ba60Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0
806f6ba60Sopenharmony_ci *
906f6ba60Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
1006f6ba60Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
1106f6ba60Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1206f6ba60Sopenharmony_ci * See the License for the specific language governing permissions and
1306f6ba60Sopenharmony_ci * limitations under the License.
1406f6ba60Sopenharmony_ci */
1506f6ba60Sopenharmony_ci#include "hidump_plugin.h"
1606f6ba60Sopenharmony_ci#include <sys/syscall.h>
1706f6ba60Sopenharmony_ci#include <sys/types.h>
1806f6ba60Sopenharmony_ci#include <unistd.h>
1906f6ba60Sopenharmony_ci#include <cstdio>
2006f6ba60Sopenharmony_ci#include <cstring>
2106f6ba60Sopenharmony_ci#include <fcntl.h>
2206f6ba60Sopenharmony_ci#include <cinttypes>
2306f6ba60Sopenharmony_ci#include <csignal>
2406f6ba60Sopenharmony_ci#include <sstream>
2506f6ba60Sopenharmony_ci#include <sys/wait.h>
2606f6ba60Sopenharmony_ci
2706f6ba60Sopenharmony_ci#include "hidump_plugin_result.pbencoder.h"
2806f6ba60Sopenharmony_ci#include "securec.h"
2906f6ba60Sopenharmony_ci#include "common.h"
3006f6ba60Sopenharmony_ci
3106f6ba60Sopenharmony_cinamespace {
3206f6ba60Sopenharmony_ciusing namespace OHOS::Developtools::Profiler;
3306f6ba60Sopenharmony_ciconst int SLEEP_TIME = 50;
3406f6ba60Sopenharmony_ciconst int BUF_MAX_LEN = 64;
3506f6ba60Sopenharmony_ciconst int MS_PER_S = 1000;
3606f6ba60Sopenharmony_ciconst int US_PER_S = 1000000;
3706f6ba60Sopenharmony_ciconst char *FPS_FORMAT = "SP_daemon -profilerfps 31104000 -sections 10";
3806f6ba60Sopenharmony_ci
3906f6ba60Sopenharmony_ci} // namespace
4006f6ba60Sopenharmony_ci
4106f6ba60Sopenharmony_ciHidumpPlugin::HidumpPlugin() : fp_(nullptr, nullptr) {}
4206f6ba60Sopenharmony_ci
4306f6ba60Sopenharmony_ciHidumpPlugin::~HidumpPlugin()
4406f6ba60Sopenharmony_ci{
4506f6ba60Sopenharmony_ci    PROFILER_LOG_INFO(LOG_CORE, "%s: ready!", __func__);
4606f6ba60Sopenharmony_ci    std::unique_lock<std::mutex> locker(mutex_);
4706f6ba60Sopenharmony_ci    if (running_) {
4806f6ba60Sopenharmony_ci        running_ = false;
4906f6ba60Sopenharmony_ci        if (writeThread_.joinable()) {
5006f6ba60Sopenharmony_ci            writeThread_.join();
5106f6ba60Sopenharmony_ci        }
5206f6ba60Sopenharmony_ci    }
5306f6ba60Sopenharmony_ci    locker.unlock();
5406f6ba60Sopenharmony_ci
5506f6ba60Sopenharmony_ci    if (fp_ != nullptr) {
5606f6ba60Sopenharmony_ci        fp_.reset();
5706f6ba60Sopenharmony_ci    }
5806f6ba60Sopenharmony_ci    PROFILER_LOG_INFO(LOG_CORE, "%s: success!", __func__);
5906f6ba60Sopenharmony_ci}
6006f6ba60Sopenharmony_ci
6106f6ba60Sopenharmony_ciint HidumpPlugin::Start(const uint8_t* configData, uint32_t configSize)
6206f6ba60Sopenharmony_ci{
6306f6ba60Sopenharmony_ci    PROFILER_LOG_INFO(LOG_CORE, "HidumpPlugin:Start ----> !");
6406f6ba60Sopenharmony_ci    CHECK_TRUE(protoConfig_.ParseFromArray(configData, configSize) > 0, -1, "HidumpPlugin: ParseFromArray failed");
6506f6ba60Sopenharmony_ci    std::vector<std::string> fullCmd;
6606f6ba60Sopenharmony_ci    fullCmd.push_back("/system/bin/SP_daemon");
6706f6ba60Sopenharmony_ci    fullCmd.push_back("SP_daemon");
6806f6ba60Sopenharmony_ci    fullCmd.push_back("-profilerfps");
6906f6ba60Sopenharmony_ci    fullCmd.push_back("31104000");
7006f6ba60Sopenharmony_ci    fullCmd.push_back("-sections");
7106f6ba60Sopenharmony_ci    fullCmd.push_back(std::to_string(protoConfig_.sections()));
7206f6ba60Sopenharmony_ci    fp_ = std::unique_ptr<FILE, std::function<int (FILE*)>>(
7306f6ba60Sopenharmony_ci        COMMON::CustomPopen(fullCmd, "r", pipeFds_, childPid_, true), [this](FILE* fp) -> int {
7406f6ba60Sopenharmony_ci            return COMMON::CustomPclose(fp, pipeFds_, childPid_, true);
7506f6ba60Sopenharmony_ci        });
7606f6ba60Sopenharmony_ci    if (fp_.get() == nullptr) {
7706f6ba60Sopenharmony_ci        const int bufSize = 256;
7806f6ba60Sopenharmony_ci        char buf[bufSize] = {0};
7906f6ba60Sopenharmony_ci        strerror_r(errno, buf, bufSize);
8006f6ba60Sopenharmony_ci        PROFILER_LOG_ERROR(LOG_CORE, "HidumpPlugin: CustomPopen(%s) Failed, errno(%d:%s)", FPS_FORMAT, errno, buf);
8106f6ba60Sopenharmony_ci        return -1;
8206f6ba60Sopenharmony_ci    }
8306f6ba60Sopenharmony_ci    CHECK_NOTNULL(resultWriter_, -1, "HidumpPlugin: Writer is no set!");
8406f6ba60Sopenharmony_ci    CHECK_NOTNULL(resultWriter_->write, -1, "HidumpPlugin: Writer.write is no set!");
8506f6ba60Sopenharmony_ci    CHECK_NOTNULL(resultWriter_->flush, -1, "HidumpPlugin: Writer.flush is no set!");
8606f6ba60Sopenharmony_ci    std::unique_lock<std::mutex> locker(mutex_);
8706f6ba60Sopenharmony_ci    running_ = true;
8806f6ba60Sopenharmony_ci    writeThread_ = std::thread([this] { this->Loop(); });
8906f6ba60Sopenharmony_ci    PROFILER_LOG_INFO(LOG_CORE, "HidumpPlugin: ---> Start success!");
9006f6ba60Sopenharmony_ci    return 0;
9106f6ba60Sopenharmony_ci}
9206f6ba60Sopenharmony_ci
9306f6ba60Sopenharmony_ciint HidumpPlugin::Stop()
9406f6ba60Sopenharmony_ci{
9506f6ba60Sopenharmony_ci    std::unique_lock<std::mutex> locker(mutex_);
9606f6ba60Sopenharmony_ci    running_ = false;
9706f6ba60Sopenharmony_ci    locker.unlock();
9806f6ba60Sopenharmony_ci    if (writeThread_.joinable()) {
9906f6ba60Sopenharmony_ci        writeThread_.join();
10006f6ba60Sopenharmony_ci    }
10106f6ba60Sopenharmony_ci    PROFILER_LOG_INFO(LOG_CORE, "HidumpPlugin:stop thread success!");
10206f6ba60Sopenharmony_ci    if (fp_ != nullptr) {
10306f6ba60Sopenharmony_ci        fp_.reset();
10406f6ba60Sopenharmony_ci    }
10506f6ba60Sopenharmony_ci    PROFILER_LOG_INFO(LOG_CORE, "HidumpPlugin: stop success!");
10606f6ba60Sopenharmony_ci    return 0;
10706f6ba60Sopenharmony_ci}
10806f6ba60Sopenharmony_ci
10906f6ba60Sopenharmony_ciint HidumpPlugin::SetWriter(WriterStruct* writer)
11006f6ba60Sopenharmony_ci{
11106f6ba60Sopenharmony_ci    resultWriter_ = writer;
11206f6ba60Sopenharmony_ci    return 0;
11306f6ba60Sopenharmony_ci}
11406f6ba60Sopenharmony_ci
11506f6ba60Sopenharmony_civoid HidumpPlugin::Loop(void)
11606f6ba60Sopenharmony_ci{
11706f6ba60Sopenharmony_ci    PROFILER_LOG_INFO(LOG_CORE, "HidumpPlugin: Loop start");
11806f6ba60Sopenharmony_ci    CHECK_NOTNULL(resultWriter_, NO_RETVAL, "%s: resultWriter_ nullptr", __func__);
11906f6ba60Sopenharmony_ci
12006f6ba60Sopenharmony_ci    fcntl(fileno(fp_.get()), F_SETFL, O_NONBLOCK);
12106f6ba60Sopenharmony_ci    while (running_) {
12206f6ba60Sopenharmony_ci        char buf[BUF_MAX_LEN] = { 0 };
12306f6ba60Sopenharmony_ci
12406f6ba60Sopenharmony_ci        if (fgets(buf, BUF_MAX_LEN - 1, fp_.get()) == nullptr) {
12506f6ba60Sopenharmony_ci            std::this_thread::sleep_for(std::chrono::milliseconds(SLEEP_TIME));
12606f6ba60Sopenharmony_ci            continue;
12706f6ba60Sopenharmony_ci        }
12806f6ba60Sopenharmony_ci        char* pTempBuf = buf;
12906f6ba60Sopenharmony_ci        if (strncmp(pTempBuf, "fps:", strlen("fps:")) == 0) {
13006f6ba60Sopenharmony_ci            pTempBuf += strlen("fps:");
13106f6ba60Sopenharmony_ci            std::string stringBuf(pTempBuf);
13206f6ba60Sopenharmony_ci            size_t npos = stringBuf.find("|");
13306f6ba60Sopenharmony_ci            uint32_t fps = static_cast<uint32_t>(std::stoi(stringBuf.substr(0, npos)));
13406f6ba60Sopenharmony_ci            if (fps > 0) {
13506f6ba60Sopenharmony_ci                continue;
13606f6ba60Sopenharmony_ci            }
13706f6ba60Sopenharmony_ci        }
13806f6ba60Sopenharmony_ci        if (resultWriter_->isProtobufSerialize) {
13906f6ba60Sopenharmony_ci            HidumpInfo dataProto;
14006f6ba60Sopenharmony_ci            if (!ParseHidumpInfo(dataProto, buf, sizeof(buf))) {
14106f6ba60Sopenharmony_ci                continue;
14206f6ba60Sopenharmony_ci            }
14306f6ba60Sopenharmony_ci            if (dataProto.ByteSizeLong() > 0) {
14406f6ba60Sopenharmony_ci                buffer_.resize(dataProto.ByteSizeLong());
14506f6ba60Sopenharmony_ci                dataProto.SerializeToArray(buffer_.data(), buffer_.size());
14606f6ba60Sopenharmony_ci                resultWriter_->write(resultWriter_, buffer_.data(), buffer_.size());
14706f6ba60Sopenharmony_ci                resultWriter_->flush(resultWriter_);
14806f6ba60Sopenharmony_ci            }
14906f6ba60Sopenharmony_ci        } else {
15006f6ba60Sopenharmony_ci            ProtoEncoder::HidumpInfo hidumpInfo(resultWriter_->startReport(resultWriter_));
15106f6ba60Sopenharmony_ci            if (!ParseHidumpInfo(hidumpInfo, buf, sizeof(buf))) {
15206f6ba60Sopenharmony_ci                PROFILER_LOG_ERROR(LOG_CORE, "parse hidump info failed!");
15306f6ba60Sopenharmony_ci            }
15406f6ba60Sopenharmony_ci            int messageLen = hidumpInfo.Finish();
15506f6ba60Sopenharmony_ci            resultWriter_->finishReport(resultWriter_, messageLen);
15606f6ba60Sopenharmony_ci            resultWriter_->flush(resultWriter_);
15706f6ba60Sopenharmony_ci        }
15806f6ba60Sopenharmony_ci    }
15906f6ba60Sopenharmony_ci
16006f6ba60Sopenharmony_ci    PROFILER_LOG_INFO(LOG_CORE, "HidumpPlugin: Loop exit");
16106f6ba60Sopenharmony_ci}
16206f6ba60Sopenharmony_ci
16306f6ba60Sopenharmony_citemplate <typename T>
16406f6ba60Sopenharmony_cibool HidumpPlugin::ParseHidumpInfo(T& hidumpInfoProto, char *buf, size_t len)
16506f6ba60Sopenharmony_ci{
16606f6ba60Sopenharmony_ci    UNUSED_PARAMETER(len);
16706f6ba60Sopenharmony_ci    // format: fps:123|1501960484673
16806f6ba60Sopenharmony_ci    if (strncmp(buf, "fps:", strlen("fps:")) != 0 && strncmp(buf, "sectionsFps:", strlen("sectionsFps:")) != 0) {
16906f6ba60Sopenharmony_ci        if (strstr(buf, "inaccessible or not found") != nullptr) {
17006f6ba60Sopenharmony_ci            PROFILER_LOG_ERROR(LOG_CORE, "HidumpPlugin: fps command not found!");
17106f6ba60Sopenharmony_ci        } else {
17206f6ba60Sopenharmony_ci            PROFILER_LOG_ERROR(LOG_CORE, "format error. %s", buf);
17306f6ba60Sopenharmony_ci        }
17406f6ba60Sopenharmony_ci        return false;
17506f6ba60Sopenharmony_ci    }
17606f6ba60Sopenharmony_ci
17706f6ba60Sopenharmony_ci    if (strncmp(buf, "fps:", strlen("fps:")) == 0) {
17806f6ba60Sopenharmony_ci        buf += strlen("fps:");
17906f6ba60Sopenharmony_ci    } else if (strncmp(buf, "sectionsFps:", strlen("sectionsFps:")) == 0) {
18006f6ba60Sopenharmony_ci        buf += strlen("sectionsFps:");
18106f6ba60Sopenharmony_ci    }
18206f6ba60Sopenharmony_ci
18306f6ba60Sopenharmony_ci    char *tmp = strchr(buf, '|');
18406f6ba60Sopenharmony_ci    CHECK_NOTNULL(tmp, false, "format error. %s", buf);
18506f6ba60Sopenharmony_ci    *tmp = ' ';
18606f6ba60Sopenharmony_ci    std::stringstream strvalue(buf);
18706f6ba60Sopenharmony_ci    uint32_t fps = 0;
18806f6ba60Sopenharmony_ci    strvalue >> fps;
18906f6ba60Sopenharmony_ci    uint64_t time_ms;
19006f6ba60Sopenharmony_ci    strvalue >> time_ms;
19106f6ba60Sopenharmony_ci
19206f6ba60Sopenharmony_ci    auto* eve = hidumpInfoProto.add_fps_event();
19306f6ba60Sopenharmony_ci    eve->set_fps(fps);
19406f6ba60Sopenharmony_ci    eve->set_id(::FpsData::REALTIME);
19506f6ba60Sopenharmony_ci    auto* time = eve->mutable_time();
19606f6ba60Sopenharmony_ci    time->set_tv_sec(time_ms / MS_PER_S);
19706f6ba60Sopenharmony_ci    time->set_tv_nsec((time_ms % MS_PER_S) * US_PER_S);
19806f6ba60Sopenharmony_ci
19906f6ba60Sopenharmony_ci    return true;
20006f6ba60Sopenharmony_ci}
20106f6ba60Sopenharmony_ci
20206f6ba60Sopenharmony_civoid HidumpPlugin::SetConfig(HidumpConfig& config)
20306f6ba60Sopenharmony_ci{
20406f6ba60Sopenharmony_ci    protoConfig_ = config;
20506f6ba60Sopenharmony_ci}
20606f6ba60Sopenharmony_ci
20706f6ba60Sopenharmony_ciint HidumpPlugin::SetTestCmd(const char *test_cmd)
20806f6ba60Sopenharmony_ci{
20906f6ba60Sopenharmony_ci    CHECK_NOTNULL(test_cmd, -1, "HidumpPlugin:%s test_cmd is null", __func__);
21006f6ba60Sopenharmony_ci    testCmd_ = const_cast<char *>(test_cmd);
21106f6ba60Sopenharmony_ci    return 0;
21206f6ba60Sopenharmony_ci}
21306f6ba60Sopenharmony_ci
21406f6ba60Sopenharmony_ciconst char *HidumpPlugin::GetTestCmd(void)
21506f6ba60Sopenharmony_ci{
21606f6ba60Sopenharmony_ci    return testCmd_;
21706f6ba60Sopenharmony_ci}
218