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