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