• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022 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 "hisysevent_plugin.h"
16 
17 #include <fcntl.h>
18 #include <cinttypes>
19 #include <csignal>
20 #include <sstream>
21 #include <cstdio>
22 #include <sys/syscall.h>
23 #include <sys/types.h>
24 #include <sys/wait.h>
25 #include <unistd.h>
26 
27 namespace {
28     constexpr int PIPE_LEN = 2;
29 
30     constexpr int READ = 0;
31     constexpr int WRITE = 1;
32     static pid_t volatile g_child;
33 
34     constexpr int MAX_STRING_LEN = 256 * 1024;
35     constexpr int MIN_STRING_LEN = 10;
36     constexpr int BYTE_BUFFER_SIZE = 1024;
37 
38     std::atomic<uint64_t> g_id(1);
39 }
40 
HisyseventPlugin()41 HisyseventPlugin::HisyseventPlugin():fp_(nullptr, nullptr) {}
42 
~HisyseventPlugin()43 HisyseventPlugin::~HisyseventPlugin()
44 {
45     HILOG_INFO(LOG_CORE, "BEGN %s: ready!", __func__);
46     std::unique_lock<std::mutex> locker(mutex_);
47 
48     if (running_) {
49         running_ = false;
50         if (workThread_.joinable()) {
51             workThread_.join();
52         }
53     }
54 
55     locker.unlock();
56 
57     if (fp_ != nullptr) {
58         fp_.reset();
59     }
60 
61     HILOG_INFO(LOG_CORE, "END %s: success!", __func__);
62 }
63 
SetWriter(WriterStruct * writer)64 int HisyseventPlugin::SetWriter(WriterStruct* writer)
65 {
66     resultWriter_ = writer;
67 
68     HILOG_INFO(LOG_CORE, "END %s: success!", __func__);
69     return 0;
70 }
71 
Start(const uint8_t * configData,uint32_t configSize)72 int HisyseventPlugin::Start(const uint8_t* configData, uint32_t configSize)
73 {
74     HILOG_INFO(LOG_CORE, "BEGN %s: ready!", __func__);
75     if (configData == nullptr || configSize <= 0) {
76         HILOG_ERROR(LOG_CORE, "NOTE %s: param invalid", __func__);
77         return -1;
78     }
79 
80     if (protoConfig_.ParseFromArray(configData, configSize) <= 0) {
81         HILOG_ERROR(LOG_CORE, "NOTE HisyseventPlugin: ParseFromArray failed");
82         return -1;
83     }
84 
85     HILOG_DEBUG(LOG_CORE, "NOTE configData ParseFromArray sucessed,sourse data:%s", protoConfig_.msg().c_str());
86 
87     if (!InitHisyseventCmd()) {
88         HILOG_ERROR(LOG_CORE, "TODO HisyseventPlugin: Init HisyseventCmd failed");
89         return -1;
90     }
91 
92     fp_ = std::unique_ptr<FILE, int (*)(FILE*)>(CustomPopen(&fullCmd_[0], "r"), CustomPclose);
93     CHECK_NOTNULL(fp_.get(), -1, "HisyseventPlugin: fullCmd_ Failed, errno(%d)", errno);
94     CHECK_NOTNULL(resultWriter_, -1, "HisyseventPlugin: Writer is no set!!");
95     CHECK_NOTNULL(resultWriter_->write, -1, "HisyseventPlugin: Writer.write is no set!!");
96     CHECK_NOTNULL(resultWriter_->flush, -1, "HisyseventPlugin: Writer.flush is no set!!");
97 
98     g_id = 1;
99     std::unique_lock<std::mutex> locker(mutex_);
100     running_ = true;
101     workThread_ = std::thread(&HisyseventPlugin::Run, this);
102 
103     HILOG_INFO(LOG_CORE, "END %s: success!", __func__);
104     return 0;
105 }
106 
Stop()107 int HisyseventPlugin::Stop()
108 {
109     HILOG_INFO(LOG_CORE, "BEGN %s: ready!", __func__);
110     std::unique_lock<std::mutex> locker(mutex_);
111     running_ = false;
112     locker.unlock();
113     if (workThread_.joinable()) {
114         workThread_.join();
115     }
116     HILOG_INFO(LOG_CORE, "HisyseventPlugin: stop thread success!");
117 
118     fp_.reset();
119 
120     HILOG_INFO(LOG_CORE, "END %s: success!", __func__);
121     return 0;
122 }
123 
Run(void)124 void HisyseventPlugin::Run(void)
125 {
126     HILOG_INFO(LOG_CORE, "BEGN %s: ready!", __func__);
127     std::unique_ptr<uint8_t[]> buffer = std::make_unique<uint8_t[]>(MAX_STRING_LEN);
128 
129     if (buffer == nullptr) {
130         return;
131     }
132 
133     HILOG_DEBUG(LOG_CORE, "NOTE hisysevent_plugin_result.proto->HisyseventInfo:dataProto;Ready to output the result!");
134     HisyseventInfo dataProto;
135     fcntl(fileno(fp_.get()), F_SETFL, O_NONBLOCK);
136 
137     while (running_) {
138         if (fgets(reinterpret_cast<char*>(buffer.get()), MAX_STRING_LEN, fp_.get()) != nullptr) {
139             auto cptr = reinterpret_cast<char*>(buffer.get());
140             if (!ParseSyseventLineInfo(cptr, strlen(cptr), dataProto))
141                 continue;
142         }
143 
144         if (dataProto.ByteSizeLong() >= BYTE_BUFFER_SIZE) {
145             // Cmd result resize and SerializeToArray and after save to protoBuffer_ ;write and flush;clear_info
146             protoBuffer_.resize(dataProto.ByteSizeLong());
147             dataProto.SerializeToArray(protoBuffer_.data(), protoBuffer_.size());
148 
149             // SerializeToArray after data=%s",protoBuffer_.data()
150             resultWriter_->write(resultWriter_, protoBuffer_.data(), protoBuffer_.size());
151             resultWriter_->flush(resultWriter_);
152             dataProto.clear_info();
153         }
154     }
155 
156     protoBuffer_.resize(dataProto.ByteSizeLong());
157     dataProto.SerializeToArray(protoBuffer_.data(), protoBuffer_.size());
158     resultWriter_->write(resultWriter_, protoBuffer_.data(), protoBuffer_.size());
159     resultWriter_->flush(resultWriter_);
160     dataProto.clear_info();
161 
162     HILOG_INFO(LOG_CORE, "END %s: success!", __func__);
163 }
164 
ParseSyseventLineInfo(const char * data,size_t len,HisyseventInfo & dataProto)165 inline bool HisyseventPlugin::ParseSyseventLineInfo(const char* data, size_t len, HisyseventInfo& dataProto)
166 {
167     if (data == nullptr || len < MIN_STRING_LEN) {
168         HILOG_ERROR(LOG_CORE, "NOTE %s: param invalid", __func__);
169         return false;
170     }
171 
172     if (google::protobuf::internal::IsStructurallyValidUTF8(data, strlen(data) - 1)) {
173         auto* info = dataProto.add_info();
174         info->set_id(g_id);
175         info->set_context(data, strlen(data) - 1);  // - \n
176         g_id++;
177     } else {
178         HILOG_ERROR(LOG_CORE, "NOTE HisyseventPlugin: hisysevent context include invalid UTF-8 data");
179         return false;
180     }
181 
182     return true;
183 }
184 
InitHisyseventCmd()185 inline bool HisyseventPlugin::InitHisyseventCmd()
186 {
187     HILOG_INFO(LOG_CORE, "BEGN %s: ready!", __func__);
188     if (fullCmd_.size() > 0) {
189         HILOG_INFO(LOG_CORE, "fullCmd_ is dirty.Clear().");
190         fullCmd_.clear();
191     }
192 
193     fullCmd_.push_back(const_cast<char *>("hisysevent"));
194     fullCmd_.push_back(const_cast<char *>("-rd"));
195     fullCmd_.push_back(nullptr);
196 
197     HILOG_INFO(LOG_CORE, "END %s: success!", __func__);
198     return true;
199 }
200 
GetCmdline()201 std::string HisyseventPlugin::GetCmdline()
202 {
203     std::string cmdline;
204     for (size_t i = 0; i < fullCmd_.size() - 1 ; i++)
205         cmdline.append(fullCmd_[i]).append(" ");
206 
207     HILOG_INFO(LOG_CORE, "END %s: success!", __func__);
208     return cmdline;
209 }
210 
CustomPopen(char * const command[],const char * type)211 FILE* HisyseventPlugin::CustomPopen(char* const command[], const char* type)
212 {
213     HILOG_INFO(LOG_CORE, "BEGN %s: ready!", __func__);
214     if (command == nullptr || type == nullptr) {
215         HILOG_ERROR(LOG_CORE, "HisyseventPlugin:%s param invalid", __func__);
216         return nullptr;
217     }
218 
219     int fd[PIPE_LEN];
220     pipe(fd);
221 
222     pid_t pid = fork();
223     if (pid == -1) {
224         perror("fork");
225         exit(1);
226     }
227 
228     if (pid == 0) {
229         if (!strncmp(type, "r", strlen(type))) {
230             close(fd[READ]);
231             dup2(fd[WRITE], 1); // Redirect stdout to pipe
232             dup2(fd[WRITE], 2); // 2: Redirect stderr to pipe
233         } else {
234             close(fd[WRITE]);
235             dup2(fd[READ], 0); // Redirect stdin to pipe
236         }
237         setpgid(pid, pid);
238         execvp("hisysevent", &command[0]);
239         exit(0);
240     } else {
241         if (!strncmp(type, "r", strlen(type))) {
242             // Close the WRITE end of the pipe since parent's fd is read-only
243             close(fd[WRITE]);
244         } else {
245             // Close the READ end of the pipe since parent's fd is write-only
246             close(fd[READ]);
247         }
248     }
249 
250     g_child = pid;
251 
252     if (!strncmp(type, "r", strlen(type))) {
253         return fdopen(fd[READ], "r");
254     }
255 
256     HILOG_INFO(LOG_CORE, "END %s: success!", __func__);
257     return fdopen(fd[WRITE], "w");
258 }
259 
CustomPclose(FILE * fp)260 int HisyseventPlugin::CustomPclose(FILE* fp)
261 {
262     HILOG_INFO(LOG_CORE, "BEGN %s: ready!", __func__);
263     CHECK_NOTNULL(fp, -1, "NOTE %s: fp is null", __func__);
264 
265     int stat = 0;
266     int ret = fclose(fp);
267     CHECK_TRUE(ret == 0, -1, "NOTE %s: fclose failed! errno(%d)", __func__, errno);
268     kill(g_child, SIGKILL);
269     if (waitpid(g_child, &stat, 0) == -1) {
270         if (errno != EINTR) {
271             return stat;
272         }
273     }
274 
275     HILOG_INFO(LOG_CORE, "END %s: success!", __func__);
276     return stat;
277 }
278