• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) Huawei Technologies Co., Ltd. 2021. All rights reserved.
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 #include "hidump_plugin.h"
16 #include <sys/syscall.h>
17 #include <sys/types.h>
18 #include <unistd.h>
19 #include <cstdio>
20 #include <cstring>
21 #include <fcntl.h>
22 #include <cinttypes>
23 #include <csignal>
24 #include <sstream>
25 #include <sys/wait.h>
26 
27 #include "common.h"
28 #include "hidump_plugin_result.pbencoder.h"
29 #include "hisysevent.h"
30 #include "securec.h"
31 
32 namespace {
33 using namespace OHOS::Developtools::Profiler;
34 const int SLEEP_TIME = 50;
35 const int BUF_MAX_LEN = 64;
36 const int MS_PER_S = 1000;
37 const int US_PER_S = 1000000;
38 const char *FPS_FORMAT = "SP_daemon -profilerfps 31104000 -sections 10";
39 
40 } // namespace
41 
HidumpPlugin()42 HidumpPlugin::HidumpPlugin() : fp_(nullptr, nullptr) {}
43 
~HidumpPlugin()44 HidumpPlugin::~HidumpPlugin()
45 {
46     PROFILER_LOG_INFO(LOG_CORE, "%s: ready!", __func__);
47     std::unique_lock<std::mutex> locker(mutex_);
48     if (running_) {
49         running_ = false;
50         if (writeThread_.joinable()) {
51             writeThread_.join();
52         }
53     }
54     locker.unlock();
55 
56     if (fp_ != nullptr) {
57         fp_.reset();
58     }
59     PROFILER_LOG_INFO(LOG_CORE, "%s: success!", __func__);
60 }
61 
GetCmdArgs(const HidumpConfig & protoConfig)62 std::string HidumpPlugin::GetCmdArgs(const HidumpConfig& protoConfig)
63 {
64     std::string args;
65     args += "sections: " + std::to_string(protoConfig.sections()) + ", report_fps: ";
66     args += (protoConfig.report_fps() ? "true" : "false");
67     return args;
68 }
69 
Start(const uint8_t * configData,uint32_t configSize)70 int HidumpPlugin::Start(const uint8_t* configData, uint32_t configSize)
71 {
72     PROFILER_LOG_INFO(LOG_CORE, "HidumpPlugin:Start ----> !");
73     CHECK_TRUE(protoConfig_.ParseFromArray(configData, configSize) > 0, -1, "HidumpPlugin: ParseFromArray failed");
74     std::vector<std::string> fullCmd;
75     fullCmd.push_back("/system/bin/SP_daemon");
76     fullCmd.push_back("SP_daemon");
77     fullCmd.push_back("-profilerfps");
78     fullCmd.push_back("31104000");
79     fullCmd.push_back("-sections");
80     fullCmd.push_back(std::to_string(protoConfig_.sections()));
81     fp_ = std::unique_ptr<FILE, std::function<int (FILE*)>>(
82         COMMON::CustomPopen(fullCmd, "r", pipeFds_, childPid_, true), [this](FILE* fp) -> int {
83             return COMMON::CustomPclose(fp, pipeFds_, childPid_, true);
84         });
85     auto args = GetCmdArgs(protoConfig_);
86     if (fp_.get() == nullptr) {
87         const int bufSize = 256;
88         char buf[bufSize] = {0};
89         strerror_r(errno, buf, bufSize);
90         COMMON::PluginWriteToHisysevent("hidump_plugin", "sh", args, COMMON::ErrorType::RET_FAIL, "failed");
91         PROFILER_LOG_ERROR(LOG_CORE, "HidumpPlugin: CustomPopen(%s) Failed, errno(%d:%s)", FPS_FORMAT, errno, buf);
92         return -1;
93     }
94     CHECK_NOTNULL(resultWriter_, -1, "HidumpPlugin: Writer is no set!");
95     CHECK_NOTNULL(resultWriter_->write, -1, "HidumpPlugin: Writer.write is no set!");
96     CHECK_NOTNULL(resultWriter_->flush, -1, "HidumpPlugin: Writer.flush is no set!");
97     std::unique_lock<std::mutex> locker(mutex_);
98     running_ = true;
99     writeThread_ = std::thread([this] { this->Loop(); });
100     int ret = COMMON::PluginWriteToHisysevent("hidump_plugin", "sh", args, COMMON::ErrorType::RET_SUCC, "success");
101     PROFILER_LOG_INFO(LOG_CORE, "HidumpPlugin--> Start success! hisysevent report hidump_plugin result:%d", ret);
102     return 0;
103 }
104 
Stop()105 int HidumpPlugin::Stop()
106 {
107     std::unique_lock<std::mutex> locker(mutex_);
108     running_ = false;
109     locker.unlock();
110     if (writeThread_.joinable()) {
111         writeThread_.join();
112     }
113     PROFILER_LOG_INFO(LOG_CORE, "HidumpPlugin:stop thread success!");
114     if (fp_ != nullptr) {
115         fp_.reset();
116     }
117     PROFILER_LOG_INFO(LOG_CORE, "HidumpPlugin: stop success!");
118     return 0;
119 }
120 
SetWriter(WriterStruct * writer)121 int HidumpPlugin::SetWriter(WriterStruct* writer)
122 {
123     resultWriter_ = writer;
124     return 0;
125 }
126 
Loop(void)127 void HidumpPlugin::Loop(void)
128 {
129     PROFILER_LOG_INFO(LOG_CORE, "HidumpPlugin: Loop start");
130     CHECK_NOTNULL(resultWriter_, NO_RETVAL, "%s: resultWriter_ nullptr", __func__);
131 
132     fcntl(fileno(fp_.get()), F_SETFL, O_NONBLOCK);
133     while (running_) {
134         char buf[BUF_MAX_LEN] = { 0 };
135 
136         if (fgets(buf, BUF_MAX_LEN - 1, fp_.get()) == nullptr) {
137             std::this_thread::sleep_for(std::chrono::milliseconds(SLEEP_TIME));
138             continue;
139         }
140         char* pTempBuf = buf;
141         if (strncmp(pTempBuf, "fps:", strlen("fps:")) == 0) {
142             pTempBuf += strlen("fps:");
143             std::string stringBuf(pTempBuf);
144             size_t npos = stringBuf.find("|");
145             uint32_t fps = static_cast<uint32_t>(std::stoi(stringBuf.substr(0, npos)));
146             if (fps > 0) {
147                 continue;
148             }
149         }
150         if (resultWriter_->isProtobufSerialize) {
151             HidumpInfo dataProto;
152             if (!ParseHidumpInfo(dataProto, buf, sizeof(buf))) {
153                 continue;
154             }
155             if (dataProto.ByteSizeLong() > 0) {
156                 buffer_.resize(dataProto.ByteSizeLong());
157                 dataProto.SerializeToArray(buffer_.data(), buffer_.size());
158                 resultWriter_->write(resultWriter_, buffer_.data(), buffer_.size());
159                 resultWriter_->flush(resultWriter_);
160                 if (!dataReady_) {
161                     dataReady_ = true;
162                 }
163             }
164         } else {
165             ProtoEncoder::HidumpInfo hidumpInfo(resultWriter_->startReport(resultWriter_));
166             if (!ParseHidumpInfo(hidumpInfo, buf, sizeof(buf))) {
167                 PROFILER_LOG_ERROR(LOG_CORE, "parse hidump info failed!");
168             }
169             int messageLen = hidumpInfo.Finish();
170             if (!dataReady_ && messageLen > 0) {
171                 dataReady_ = true;
172             }
173             resultWriter_->finishReport(resultWriter_, messageLen);
174             resultWriter_->flush(resultWriter_);
175         }
176     }
177 
178     PROFILER_LOG_INFO(LOG_CORE, "HidumpPlugin: Loop exit");
179 }
180 
181 template <typename T>
ParseHidumpInfo(T & hidumpInfoProto,char * buf,size_t len)182 bool HidumpPlugin::ParseHidumpInfo(T& hidumpInfoProto, char *buf, size_t len)
183 {
184     UNUSED_PARAMETER(len);
185     // format: fps:123|1501960484673
186     if (strncmp(buf, "fps:", strlen("fps:")) != 0 && strncmp(buf, "sectionsFps:", strlen("sectionsFps:")) != 0) {
187         if (strstr(buf, "inaccessible or not found") != nullptr) {
188             PROFILER_LOG_ERROR(LOG_CORE, "HidumpPlugin: fps command not found!");
189         } else {
190             PROFILER_LOG_ERROR(LOG_CORE, "format error. %s", buf);
191         }
192         return false;
193     }
194 
195     if (strncmp(buf, "fps:", strlen("fps:")) == 0) {
196         buf += strlen("fps:");
197     } else if (strncmp(buf, "sectionsFps:", strlen("sectionsFps:")) == 0) {
198         buf += strlen("sectionsFps:");
199     }
200 
201     char *tmp = strchr(buf, '|');
202     CHECK_NOTNULL(tmp, false, "format error. %s", buf);
203     *tmp = ' ';
204     std::stringstream strvalue(buf);
205     uint32_t fps = 0;
206     strvalue >> fps;
207     uint64_t time_ms;
208     strvalue >> time_ms;
209 
210     auto* eve = hidumpInfoProto.add_fps_event();
211     eve->set_fps(fps);
212     eve->set_id(::FpsData::REALTIME);
213     auto* time = eve->mutable_time();
214     time->set_tv_sec(time_ms / MS_PER_S);
215     time->set_tv_nsec((time_ms % MS_PER_S) * US_PER_S);
216 
217     return true;
218 }
219 
SetConfig(HidumpConfig & config)220 void HidumpPlugin::SetConfig(HidumpConfig& config)
221 {
222     protoConfig_ = config;
223 }
224 
SetTestCmd(const char * test_cmd)225 int HidumpPlugin::SetTestCmd(const char *test_cmd)
226 {
227     CHECK_NOTNULL(test_cmd, -1, "HidumpPlugin:%s test_cmd is null", __func__);
228     testCmd_ = const_cast<char *>(test_cmd);
229     return 0;
230 }
231 
GetTestCmd(void)232 const char *HidumpPlugin::GetTestCmd(void)
233 {
234     return testCmd_;
235 }
236