1 /*
2 * Copyright (c) Huawei Technologies Co., Ltd. 2022. 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 "hisysevent_plugin.h"
16 #include "hisysevent_plugin_result.pbencoder.h"
17
18 #include <cinttypes>
19 #include <csignal>
20 #include <cstdio>
21 #include <fcntl.h>
22 #include <sstream>
23 #include <sys/syscall.h>
24 #include <sys/types.h>
25 #include <sys/wait.h>
26 #include <unistd.h>
27 #include "utf8_validity.h"
28
29 namespace {
30 using namespace OHOS::Developtools::Profiler;
31 constexpr int PIPE_SIZE = 256 * 1024;
32 constexpr int MAX_STRING_LEN = 256 * 1024;
33 constexpr int MIN_STRING_LEN = 10;
34 constexpr int BYTE_BUFFER_SIZE = 1024;
35 } // namespace
36
HisyseventPlugin()37 HisyseventPlugin::HisyseventPlugin() : fp_(nullptr, nullptr) {}
38
~HisyseventPlugin()39 HisyseventPlugin::~HisyseventPlugin()
40 {
41 PROFILER_LOG_INFO(LOG_CORE, "BEGN %s: ready!", __func__);
42 Stop();
43 PROFILER_LOG_INFO(LOG_CORE, "END %s: success!", __func__);
44 }
45
SetWriter(WriterStruct * writer)46 int HisyseventPlugin::SetWriter(WriterStruct* writer)
47 {
48 resultWriter_ = writer;
49
50 PROFILER_LOG_INFO(LOG_CORE, "END %s: success!", __func__);
51 return 0;
52 }
53
Start(const uint8_t * configData,uint32_t configSize)54 int HisyseventPlugin::Start(const uint8_t* configData, uint32_t configSize)
55 {
56 PROFILER_LOG_INFO(LOG_CORE, "BEGN %s: ready!", __func__);
57 CHECK_NOTNULL(configData, -1, "NOTE %s: param invalid", __func__);
58
59 CHECK_TRUE(protoConfig_.ParseFromArray(configData, configSize) > 0, -1,
60 "NOTE HisyseventPlugin: ParseFromArray failed");
61
62 PROFILER_LOG_DEBUG(LOG_CORE, "config sourse data:%s domain:%s event:%s", protoConfig_.msg().c_str(),
63 protoConfig_.subscribe_domain().c_str(), protoConfig_.subscribe_event().c_str());
64
65 CHECK_TRUE(InitHisyseventCmd(), -1, "HisyseventPlugin: Init HisyseventCmd failed");
66
67 fp_ = std::unique_ptr<FILE, std::function<int (FILE*)>>(
68 COMMON::CustomPopen(fullCmd_, "r", pipeFds_, childPid_, true), [this](FILE* fp) -> int {
69 return COMMON::CustomPclose(fp, pipeFds_, childPid_, true);
70 });
71
72 CHECK_NOTNULL(fp_.get(), -1, "HisyseventPlugin: fullCmd_ Failed, errno(%d)", errno);
73 CHECK_NOTNULL(resultWriter_, -1, "HisyseventPlugin: Writer is no set!!");
74 CHECK_NOTNULL(resultWriter_->write, -1, "HisyseventPlugin: Writer.write is no set!!");
75 CHECK_NOTNULL(resultWriter_->flush, -1, "HisyseventPlugin: Writer.flush is no set!!");
76 id_ = 1;
77 running_ = true;
78 workThread_ = std::thread([this] { this->Run(); });
79
80 int ret = COMMON::PluginWriteToHisysevent("hisysevent_plugin", "sh", GetCmdArgs(protoConfig_),
81 COMMON::ErrorType::RET_SUCC, "success");
82 PROFILER_LOG_INFO(LOG_CORE, "END %s: success! hisysevent report hisysevent_plugin result:%d", __func__, ret);
83 return 0;
84 }
85
GetCmdArgs(const HisyseventConfig & protoConfig)86 std::string HisyseventPlugin::GetCmdArgs(const HisyseventConfig& protoConfig)
87 {
88 std::string args;
89 args += "msg: " + protoConfig.msg() + ", ";
90 args += "subscribe_domain: " + protoConfig.subscribe_domain() + ", ";
91 args += "subscribe_event: " + protoConfig.subscribe_event();
92 return args;
93 }
94
Stop()95 int HisyseventPlugin::Stop()
96 {
97 PROFILER_LOG_INFO(LOG_CORE, "BEGN %s: ready!", __func__);
98 running_ = false;
99 COMMON::CustomPUnblock(pipeFds_);
100
101 if (workThread_.joinable()) {
102 workThread_.join();
103 }
104
105 if (fp_ != nullptr) {
106 fp_.reset();
107 }
108
109 PROFILER_LOG_INFO(LOG_CORE, "END %s: success!", __func__);
110 return 0;
111 }
112
Run(void)113 void HisyseventPlugin::Run(void)
114 {
115 PROFILER_LOG_INFO(LOG_CORE, "BEGN %s: ready!", __func__);
116 std::unique_ptr<uint8_t[]> buffer = std::make_unique<uint8_t[]>(MAX_STRING_LEN);
117
118 PROFILER_LOG_INFO(LOG_CORE,
119 "NOTE hisysevent_plugin_result.proto->HisyseventInfo:dataProto;Ready to output the result!");
120
121 fcntl(fileno(fp_.get()), F_SETPIPE_SZ, PIPE_SIZE);
122 int aPipeSize = fcntl(fileno(fp_.get()), F_GETPIPE_SZ);
123 PROFILER_LOG_INFO(LOG_CORE, "{fp = %d, aPipeSize=%d, PIPE_SIZE=%d}", fileno(fp_.get()), aPipeSize, PIPE_SIZE);
124
125 std::unique_ptr<HisyseventInfo> dataProto = nullptr;
126 std::unique_ptr<ProtoEncoder::HisyseventInfo> hisyseventInfo = nullptr;
127 if (resultWriter_->isProtobufSerialize) {
128 dataProto = std::make_unique<HisyseventInfo>();
129 } else {
130 hisyseventInfo = std::make_unique<ProtoEncoder::HisyseventInfo>(resultWriter_->startReport(resultWriter_));
131 }
132
133 while (running_) {
134 char* cptr = nullptr;
135 if (fgets(reinterpret_cast<char*>(buffer.get()), MAX_STRING_LEN, fp_.get()) != nullptr) {
136 cptr = reinterpret_cast<char*>(buffer.get());
137 }
138 if (cptr == nullptr) {
139 continue;
140 }
141 if (resultWriter_->isProtobufSerialize) {
142 if (!ParseSyseventLineInfo(cptr, strlen(cptr), dataProto.get())) {
143 continue;
144 }
145
146 if (dataProto->ByteSizeLong() >= BYTE_BUFFER_SIZE) {
147 WriteResult(dataProto.get());
148 dataProto->clear_info();
149 }
150 } else {
151 if (!ParseSyseventLineInfo(cptr, strlen(cptr), hisyseventInfo.get())) {
152 continue;
153 }
154
155 if (hisyseventInfo->Size() >= BYTE_BUFFER_SIZE) {
156 FlushDataOptimize(hisyseventInfo.get());
157 hisyseventInfo.reset();
158 hisyseventInfo =
159 std::make_unique<ProtoEncoder::HisyseventInfo>(resultWriter_->startReport(resultWriter_));
160 }
161 }
162 }
163
164 if (resultWriter_->isProtobufSerialize) {
165 WriteResult(dataProto.get());
166 dataProto.reset();
167 } else {
168 FlushDataOptimize(hisyseventInfo.get());
169 hisyseventInfo.reset();
170 }
171
172 PROFILER_LOG_INFO(LOG_CORE, "END %s: success!", __func__);
173 }
174
GetFullCmd()175 std::string HisyseventPlugin::GetFullCmd()
176 {
177 std::string cmd;
178
179 if (!fullCmd_.empty()) {
180 size_t i = 0;
181 size_t dataLen = fullCmd_.size() > 1 ? fullCmd_.size() - 1 : 0;
182 for (size_t cmdSize = dataLen; i < cmdSize; i++) {
183 cmd.append(fullCmd_[i]).append(" ");
184 }
185 cmd.append(fullCmd_[i]);
186 }
187 return cmd;
188 }
189
InitHisyseventCmd()190 inline bool HisyseventPlugin::InitHisyseventCmd()
191 {
192 PROFILER_LOG_INFO(LOG_CORE, "BEGN %s: ready!", __func__);
193 if (!fullCmd_.empty()) {
194 PROFILER_LOG_INFO(LOG_CORE, "fullCmd_ is dirty.Then clear().");
195 fullCmd_.clear();
196 }
197
198 fullCmd_.emplace_back("/system/bin/hisysevent"); // exe file path
199 fullCmd_.emplace_back("hisysevent"); // exe file name
200 fullCmd_.emplace_back("-rd");
201
202 if (!protoConfig_.subscribe_domain().empty()) {
203 fullCmd_.emplace_back("-o");
204 fullCmd_.emplace_back(protoConfig_.subscribe_domain());
205 }
206 if (!protoConfig_.subscribe_event().empty()) {
207 fullCmd_.emplace_back("-n");
208 fullCmd_.emplace_back(protoConfig_.subscribe_event());
209 }
210 PROFILER_LOG_INFO(LOG_CORE, "END %s: success!", __func__);
211 return true;
212 }
213
214 template <typename T>
ParseSyseventLineInfo(const char * data,size_t len,T hisyseventInfoProto)215 inline bool HisyseventPlugin::ParseSyseventLineInfo(const char* data, size_t len, T hisyseventInfoProto)
216 {
217 CHECK_TRUE(data != nullptr && len >= MIN_STRING_LEN, false, "NOTE %s: param invalid", __func__);
218 size_t dataLen = strlen(data) > 1 ? strlen(data) - 1 : 0;
219 if (utf8_range::IsStructurallyValid({data, dataLen})) {
220 auto* info = hisyseventInfoProto->add_info();
221 info->set_id(id_);
222 size_t len = strlen(data) > 1 ? strlen(data) - 1 : 0;
223 info->set_context(data, len); // - \n
224 id_++;
225 } else {
226 PROFILER_LOG_ERROR(LOG_CORE, "NOTE HisyseventPlugin: hisysevent context include invalid UTF-8 data");
227 return false;
228 }
229 return true;
230 }
231
WriteResult(const T hisyseventInfoProto)232 template <typename T> inline bool HisyseventPlugin::WriteResult(const T hisyseventInfoProto)
233 {
234 // Cmd result resize and SerializeToArray and after save to protoBuffer_ ;Then write and flush;Then clear_info
235 protoBuffer_.resize(hisyseventInfoProto->ByteSizeLong());
236 hisyseventInfoProto->SerializeToArray(protoBuffer_.data(), protoBuffer_.size());
237 // SerializeToArray after data=%s",protoBuffer_.data()
238 resultWriter_->write(resultWriter_, protoBuffer_.data(), protoBuffer_.size());
239 resultWriter_->flush(resultWriter_);
240 return true;
241 }
242
FlushDataOptimize(const T hisyseventInfoProto)243 template <typename T> void HisyseventPlugin::FlushDataOptimize(const T hisyseventInfoProto)
244 {
245 int messageLen = hisyseventInfoProto->Finish();
246 resultWriter_->finishReport(resultWriter_, messageLen);
247 resultWriter_->flush(resultWriter_);
248 }
249