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