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 <cinttypes>
18 #include <csignal>
19 #include <cstdio>
20 #include <fcntl.h>
21 #include <sstream>
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_SIZE = 256 * 1024;
29 constexpr int MAX_STRING_LEN = 256 * 1024;
30 constexpr int MIN_STRING_LEN = 10;
31 constexpr int BYTE_BUFFER_SIZE = 1024;
32 } // namespace
33
HisyseventPlugin()34 HisyseventPlugin::HisyseventPlugin() : fp_(nullptr, nullptr) {}
35
~HisyseventPlugin()36 HisyseventPlugin::~HisyseventPlugin()
37 {
38 HILOG_INFO(LOG_CORE, "BEGN %s: ready!", __func__);
39 Stop();
40 HILOG_INFO(LOG_CORE, "END %s: success!", __func__);
41 }
42
SetWriter(WriterStruct * writer)43 int HisyseventPlugin::SetWriter(WriterStruct* writer)
44 {
45 resultWriter_ = writer;
46
47 HILOG_INFO(LOG_CORE, "END %s: success!", __func__);
48 return 0;
49 }
50
Start(const uint8_t * configData,uint32_t configSize)51 int HisyseventPlugin::Start(const uint8_t* configData, uint32_t configSize)
52 {
53 HILOG_INFO(LOG_CORE, "BEGN %s: ready!", __func__);
54 CHECK_NOTNULL(configData, -1, "NOTE %s: param invalid", __func__);
55
56 CHECK_TRUE(protoConfig_.ParseFromArray(configData, configSize) > 0, -1,
57 "NOTE HisyseventPlugin: ParseFromArray failed");
58
59 HILOG_DEBUG(LOG_CORE, "NOTE configData ParseFromArray sucessed,sourse data:%s", protoConfig_.msg().c_str());
60
61 CHECK_TRUE(InitHisyseventCmd(), -1, "HisyseventPlugin: Init HisyseventCmd failed");
62
63 fp_ = std::unique_ptr<FILE, std::function<int (FILE*)>>(
64 COMMON::CustomPopen(fullCmd_, "r", pipeFds_, childPid_, true), [this](FILE* fp) -> int {
65 return COMMON::CustomPclose(fp, pipeFds_, childPid_, true);
66 });
67
68 CHECK_NOTNULL(fp_.get(), -1, "HisyseventPlugin: fullCmd_ Failed, errno(%d)", errno);
69 CHECK_NOTNULL(resultWriter_, -1, "HisyseventPlugin: Writer is no set!!");
70 CHECK_NOTNULL(resultWriter_->write, -1, "HisyseventPlugin: Writer.write is no set!!");
71 CHECK_NOTNULL(resultWriter_->flush, -1, "HisyseventPlugin: Writer.flush is no set!!");
72 id_ = 1;
73 running_ = true;
74 workThread_ = std::thread(&HisyseventPlugin::Run, this);
75
76 HILOG_INFO(LOG_CORE, "END %s: success!", __func__);
77 return 0;
78 }
79
Stop()80 int HisyseventPlugin::Stop()
81 {
82 HILOG_INFO(LOG_CORE, "BEGN %s: ready!", __func__);
83 running_ = false;
84 COMMON::CustomPUnblock(pipeFds_);
85
86 if (workThread_.joinable()) {
87 workThread_.join();
88 }
89
90 if (fp_ != nullptr) {
91 fp_.reset();
92 }
93
94 HILOG_INFO(LOG_CORE, "END %s: success!", __func__);
95 return 0;
96 }
97
Run(void)98 void HisyseventPlugin::Run(void)
99 {
100 HILOG_INFO(LOG_CORE, "BEGN %s: ready!", __func__);
101 std::unique_ptr<uint8_t[]> buffer = std::make_unique<uint8_t[]>(MAX_STRING_LEN);
102
103 HILOG_INFO(LOG_CORE, "NOTE hisysevent_plugin_result.proto->HisyseventInfo:dataProto;Ready to output the result!");
104 HisyseventInfo dataProto;
105
106 fcntl(fileno(fp_.get()), F_SETPIPE_SZ, PIPE_SIZE);
107 int aPipeSize = fcntl(fileno(fp_.get()), F_GETPIPE_SZ);
108 HILOG_INFO(LOG_CORE, "{fp = %d, aPipeSize=%d, PIPE_SIZE=%d}", fileno(fp_.get()), aPipeSize, PIPE_SIZE);
109
110 while (running_) {
111 if (fgets(reinterpret_cast<char*>(buffer.get()), MAX_STRING_LEN, fp_.get()) != nullptr) {
112 auto cptr = reinterpret_cast<char*>(buffer.get());
113 if (!ParseSyseventLineInfo(cptr, strlen(cptr), dataProto))
114 continue;
115 }
116
117 if (dataProto.ByteSizeLong() >= BYTE_BUFFER_SIZE) {
118 WriteResult(dataProto);
119 dataProto.clear_info();
120 }
121 }
122
123 WriteResult(dataProto);
124 dataProto.clear_info();
125
126 HILOG_INFO(LOG_CORE, "END %s: success!", __func__);
127 }
128
GetFullCmd()129 std::string HisyseventPlugin::GetFullCmd()
130 {
131 std::string cmd;
132
133 if (!fullCmd_.empty()) {
134 size_t i = 0;
135 for (size_t cmdSize = fullCmd_.size() - 1; i < cmdSize; i++) {
136 cmd.append(fullCmd_[i]).append(" ");
137 }
138 cmd.append(fullCmd_[i]);
139 }
140 return cmd;
141 }
142
InitHisyseventCmd()143 inline bool HisyseventPlugin::InitHisyseventCmd()
144 {
145 HILOG_INFO(LOG_CORE, "BEGN %s: ready!", __func__);
146 if (!fullCmd_.empty()) {
147 HILOG_INFO(LOG_CORE, "fullCmd_ is dirty.Then clear().");
148 fullCmd_.clear();
149 }
150
151 fullCmd_.emplace_back("/bin/hisysevent"); // exe file path
152 fullCmd_.emplace_back("hisysevent"); // exe file name
153 fullCmd_.emplace_back("-rd");
154
155 HILOG_INFO(LOG_CORE, "END %s: success!", __func__);
156 return true;
157 }
158
ParseSyseventLineInfo(const char * data,size_t len,HisyseventInfo & dataProto)159 inline bool HisyseventPlugin::ParseSyseventLineInfo(const char* data, size_t len, HisyseventInfo& dataProto)
160 {
161 CHECK_TRUE(data != nullptr && len >= MIN_STRING_LEN, false, "NOTE %s: param invalid", __func__);
162
163 if (google::protobuf::internal::IsStructurallyValidUTF8(data, strlen(data) - 1)) {
164 auto* info = dataProto.add_info();
165 info->set_id(id_);
166 info->set_context(data, strlen(data) - 1); // - \n
167 id_++;
168 } else {
169 HILOG_ERROR(LOG_CORE, "NOTE HisyseventPlugin: hisysevent context include invalid UTF-8 data");
170 return false;
171 }
172
173 return true;
174 }
175
WriteResult(const HisyseventInfo & dataProto)176 inline bool HisyseventPlugin::WriteResult(const HisyseventInfo& dataProto)
177 {
178 // Cmd result resize and SerializeToArray and after save to protoBuffer_ ;Then write and flush;Then clear_info
179 protoBuffer_.resize(dataProto.ByteSizeLong());
180 dataProto.SerializeToArray(protoBuffer_.data(), protoBuffer_.size());
181 // SerializeToArray after data=%s",protoBuffer_.data()
182 resultWriter_->write(resultWriter_, protoBuffer_.data(), protoBuffer_.size());
183 resultWriter_->flush(resultWriter_);
184 return true;
185 }
186