• 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 #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 #include "securec.h"
27 
28 namespace {
29 const int REDIRECT_STDOUT = 1;
30 const int REDIRECT_STDERR = 2;
31 const int SLEEP_TIME = 50;
32 const int BUF_MAX_LEN = 64;
33 const int MS_PER_S = 1000;
34 const int US_PER_S = 1000000;
35 const char *g_fpsFormat = "GP_daemon_fps 31104000";
36 
37 static pid_t volatile g_child;
38 const int READ = 0;
39 const int WRITE = 1;
40 const int PIPE_LEN = 2;
41 const std::string BIN_COMMAND("/bin/sh");
42 } // namespace
43 
HidumpPlugin()44 HidumpPlugin::HidumpPlugin() : fp_(nullptr, nullptr) {}
45 
~HidumpPlugin()46 HidumpPlugin::~HidumpPlugin()
47 {
48     HILOG_INFO(LOG_CORE, "%s: ready!", __func__);
49     std::unique_lock<std::mutex> locker(mutex_);
50     if (running_) {
51         running_ = false;
52         if (writeThread_.joinable()) {
53             writeThread_.join();
54         }
55     }
56     locker.unlock();
57 
58     if (fp_ != nullptr) {
59         fp_.reset();
60     }
61     HILOG_INFO(LOG_CORE, "%s: success!", __func__);
62 }
63 
Start(const uint8_t * configData,uint32_t configSize)64 int HidumpPlugin::Start(const uint8_t* configData, uint32_t configSize)
65 {
66     HILOG_INFO(LOG_CORE, "HidumpPlugin:Start ----> !");
67     CHECK_TRUE(protoConfig_.ParseFromArray(configData, configSize) > 0, -1, "HidumpPlugin: ParseFromArray failed");
68 
69     fp_ = std::unique_ptr<FILE, int (*)(FILE*)>(CustomPopen(g_fpsFormat, "r"), CustomPclose);
70     if (fp_.get() == nullptr) {
71         const int bufSize = 256;
72         char buf[bufSize] = {0};
73         strerror_r(errno, buf, bufSize);
74         HILOG_ERROR(LOG_CORE, "HidumpPlugin: CustomPopen(%s) Failed, errno(%d:%s)", g_fpsFormat, errno, buf);
75         return -1;
76     }
77     CHECK_NOTNULL(resultWriter_, -1, "HidumpPlugin: Writer is no set!");
78     CHECK_NOTNULL(resultWriter_->write, -1, "HidumpPlugin: Writer.write is no set!");
79     CHECK_NOTNULL(resultWriter_->flush, -1, "HidumpPlugin: Writer.flush is no set!");
80     std::unique_lock<std::mutex> locker(mutex_);
81     running_ = true;
82     writeThread_ = std::thread(&HidumpPlugin::Loop, this);
83 
84     HILOG_INFO(LOG_CORE, "HidumpPlugin: ---> Start success!");
85     return 0;
86 }
87 
Stop()88 int HidumpPlugin::Stop()
89 {
90     std::unique_lock<std::mutex> locker(mutex_);
91     running_ = false;
92     locker.unlock();
93     if (writeThread_.joinable()) {
94         writeThread_.join();
95     }
96     HILOG_INFO(LOG_CORE, "HidumpPlugin:stop thread success!");
97     if (fp_ != nullptr) {
98         fp_.reset();
99     }
100     HILOG_INFO(LOG_CORE, "HidumpPlugin: stop success!");
101     return 0;
102 }
103 
SetWriter(WriterStruct * writer)104 int HidumpPlugin::SetWriter(WriterStruct* writer)
105 {
106     resultWriter_ = writer;
107     return 0;
108 }
109 
Loop(void)110 void HidumpPlugin::Loop(void)
111 {
112     HILOG_INFO(LOG_CORE, "HidumpPlugin: Loop start");
113     HidumpInfo dataProto;
114 
115     fcntl(fileno(fp_.get()), F_SETFL, O_NONBLOCK);
116     while (running_) {
117         char buf[BUF_MAX_LEN] = { 0 };
118 
119         if (fgets(buf, BUF_MAX_LEN - 1, fp_.get()) == nullptr) {
120             std::this_thread::sleep_for(std::chrono::milliseconds(SLEEP_TIME));
121             continue;
122         }
123         if (!ParseHidumpInfo(dataProto, buf)) {
124             continue;
125         }
126         if (dataProto.ByteSizeLong() > 0) {
127             buffer_.resize(dataProto.ByteSizeLong());
128             dataProto.SerializeToArray(buffer_.data(), buffer_.size());
129             resultWriter_->write(resultWriter_, buffer_.data(), buffer_.size());
130             resultWriter_->flush(resultWriter_);
131             dataProto.clear_fps_event();
132         }
133     }
134     buffer_.resize(dataProto.ByteSizeLong());
135     dataProto.SerializeToArray(buffer_.data(), buffer_.size());
136     resultWriter_->write(resultWriter_, buffer_.data(), buffer_.size());
137     resultWriter_->flush(resultWriter_);
138     dataProto.clear_fps_event();
139 
140     HILOG_INFO(LOG_CORE, "HidumpPlugin: Loop exit");
141 }
142 
ParseHidumpInfo(HidumpInfo & dataProto,char * buf)143 bool HidumpPlugin::ParseHidumpInfo(HidumpInfo& dataProto, char *buf)
144 {
145     // format: fps:123|1501960484673
146     if (strncmp(buf, "fps:", strlen("fps:")) != 0) {
147         if (strstr(buf, "inaccessible or not found") != nullptr) {
148             HILOG_ERROR(LOG_CORE, "HidumpPlugin: fps command not found!");
149         } else {
150             HILOG_ERROR(LOG_CORE, "format error. %s", buf);
151         }
152         return false;
153     }
154 
155     buf += strlen("fps:");
156     char *tmp = strchr(buf, '|');
157     CHECK_NOTNULL(tmp, false, "format error. %s", buf);
158     *tmp = ' ';
159     std::stringstream strvalue(buf);
160     uint32_t fps = 0;
161     strvalue >> fps;
162     uint64_t time_ms;
163     strvalue >> time_ms;
164 
165     auto* eve = dataProto.add_fps_event();
166     eve->set_fps(fps);
167     eve->set_id(::FpsData::REALTIME);
168     eve->mutable_time()->set_tv_sec(time_ms / MS_PER_S);
169     eve->mutable_time()->set_tv_nsec((time_ms % MS_PER_S) * US_PER_S);
170 
171     return true;
172 }
173 
CustomPopen(const char * command,const char * type)174 FILE* HidumpPlugin::CustomPopen(const char* command, const char* type)
175 {
176     CHECK_TRUE(command != nullptr && type != nullptr, nullptr, "HidumpPlugin:%s param invalid", __func__);
177 
178     int fd[PIPE_LEN];
179     pipe(fd);
180 
181     pid_t pid = fork();
182     if (pid == -1) {
183         perror("fork");
184         exit(1);
185     }
186 
187     // child process
188     if (pid == 0) {
189         if (!strncmp(type, "r", strlen(type))) {
190             close(fd[READ]);
191             dup2(fd[WRITE], REDIRECT_STDOUT); // Redirect stdout to pipe
192             dup2(fd[WRITE], REDIRECT_STDERR); // Redirect stderr to pipe
193         } else {
194             close(fd[WRITE]);
195             dup2(fd[READ], 0); // Redirect stdin to pipe
196         }
197 
198         setpgid(pid, pid);
199         execl(BIN_COMMAND.c_str(), BIN_COMMAND.c_str(), "-c", command, nullptr);
200         exit(0);
201     } else {
202         if (!strncmp(type, "r", strlen(type))) {
203             // Close the WRITE end of the pipe since parent's fd is read-only
204             close(fd[WRITE]);
205         } else {
206             // Close the READ end of the pipe since parent's fd is write-only
207             close(fd[READ]);
208         }
209     }
210 
211     g_child = pid;
212 
213     if (!strncmp(type, "r", strlen(type))) {
214         return fdopen(fd[READ], "r");
215     }
216 
217     return fdopen(fd[WRITE], "w");
218 }
219 
CustomPclose(FILE * fp)220 int HidumpPlugin::CustomPclose(FILE* fp)
221 {
222     CHECK_NOTNULL(fp, -1, "HidumpPlugin:%s fp is null", __func__);
223     int stat;
224     if (fclose(fp) != 0) {
225         const int bufSize = 256;
226         char buf[bufSize] = { 0 };
227         strerror_r(errno, buf, bufSize);
228         HILOG_ERROR(LOG_CORE, "HidumpPlugin:%s fclose failed! errno(%d:%s)", __func__, errno, buf);
229         return -1;
230     }
231     kill(g_child, SIGKILL);
232     if (waitpid(g_child, &stat, 0) == -1) {
233         if (errno != EINTR) {
234             stat = errno;
235         }
236     }
237     return stat;
238 }
239 
SetConfig(HidumpConfig & config)240 void HidumpPlugin::SetConfig(HidumpConfig& config)
241 {
242     protoConfig_ = config;
243 }
244 
SetTestCmd(const char * test_cmd)245 int HidumpPlugin::SetTestCmd(const char *test_cmd)
246 {
247     CHECK_NOTNULL(test_cmd, -1, "HidumpPlugin:%s test_cmd is null", __func__);
248     testCmd_ = const_cast<char *>(test_cmd);
249     return 0;
250 }
251 
GetTestCmd(void)252 const char *HidumpPlugin::GetTestCmd(void)
253 {
254     return testCmd_;
255 }
256