• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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     int ret = COMMON::PluginWriteToHisysevent("hisysevent_plugin", "sh", GetCmdArgs(protoConfig_),
80                                               COMMON::ErrorType::RET_SUCC, "success");
81     PROFILER_LOG_INFO(LOG_CORE, "END %s: success! hisysevent report hisysevent_plugin result:%d", __func__, ret);
82     return 0;
83 }
84 
GetCmdArgs(const HisyseventConfig & protoConfig)85 std::string HisyseventPlugin::GetCmdArgs(const HisyseventConfig& protoConfig)
86 {
87     std::string args;
88     args += "msg: " + protoConfig.msg() + ", ";
89     args += "subscribe_domain: " + protoConfig.subscribe_domain() + ", ";
90     args += "subscribe_event: " + protoConfig.subscribe_event();
91     return args;
92 }
93 
Stop()94 int HisyseventPlugin::Stop()
95 {
96     PROFILER_LOG_INFO(LOG_CORE, "BEGN %s: ready!", __func__);
97     running_ = false;
98     COMMON::CustomPUnblock(pipeFds_);
99 
100     if (workThread_.joinable()) {
101         workThread_.join();
102     }
103 
104     if (fp_ != nullptr) {
105         fp_.reset();
106     }
107 
108     PROFILER_LOG_INFO(LOG_CORE, "END %s: success!", __func__);
109     return 0;
110 }
111 
Run(void)112 void HisyseventPlugin::Run(void)
113 {
114     PROFILER_LOG_INFO(LOG_CORE, "BEGN %s: ready!", __func__);
115     std::unique_ptr<uint8_t[]> buffer = std::make_unique<uint8_t[]>(MAX_STRING_LEN);
116 
117     PROFILER_LOG_INFO(LOG_CORE,
118                       "NOTE hisysevent_plugin_result.proto->HisyseventInfo:dataProto;Ready to output the result!");
119 
120     fcntl(fileno(fp_.get()), F_SETPIPE_SZ, PIPE_SIZE);
121     int aPipeSize = fcntl(fileno(fp_.get()), F_GETPIPE_SZ);
122     PROFILER_LOG_INFO(LOG_CORE, "{fp = %d, aPipeSize=%d, PIPE_SIZE=%d}", fileno(fp_.get()), aPipeSize, PIPE_SIZE);
123 
124     std::unique_ptr<HisyseventInfo> dataProto = nullptr;
125     std::unique_ptr<ProtoEncoder::HisyseventInfo> hisyseventInfo = nullptr;
126     if (resultWriter_->isProtobufSerialize) {
127         dataProto = std::make_unique<HisyseventInfo>();
128     } else {
129         hisyseventInfo = std::make_unique<ProtoEncoder::HisyseventInfo>(resultWriter_->startReport(resultWriter_));
130     }
131 
132     while (running_) {
133         char* cptr = nullptr;
134         if (fgets(reinterpret_cast<char*>(buffer.get()), MAX_STRING_LEN, fp_.get()) != nullptr) {
135             cptr = reinterpret_cast<char*>(buffer.get());
136         }
137         if (cptr == nullptr) {
138             continue;
139         }
140         if (resultWriter_->isProtobufSerialize) {
141             if (!ParseSyseventLineInfo(cptr, strlen(cptr), dataProto.get())) {
142                 continue;
143             }
144 
145             if (dataProto->ByteSizeLong() >= BYTE_BUFFER_SIZE) {
146                 WriteResult(dataProto.get());
147                 dataProto->clear_info();
148             }
149         } else {
150             if (!ParseSyseventLineInfo(cptr, strlen(cptr), hisyseventInfo.get())) {
151                 continue;
152             }
153 
154             if (hisyseventInfo->Size() >= BYTE_BUFFER_SIZE) {
155                 FlushDataOptimize(hisyseventInfo.get());
156                 hisyseventInfo.reset();
157                 hisyseventInfo =
158                     std::make_unique<ProtoEncoder::HisyseventInfo>(resultWriter_->startReport(resultWriter_));
159             }
160         }
161     }
162 
163     if (resultWriter_->isProtobufSerialize) {
164         WriteResult(dataProto.get());
165         dataProto.reset();
166     } else {
167         FlushDataOptimize(hisyseventInfo.get());
168         hisyseventInfo.reset();
169     }
170 
171     PROFILER_LOG_INFO(LOG_CORE, "END %s: success!", __func__);
172 }
173 
GetFullCmd()174 std::string HisyseventPlugin::GetFullCmd()
175 {
176     std::string cmd;
177 
178     if (!fullCmd_.empty()) {
179         size_t i = 0;
180         size_t dataLen = fullCmd_.size() > 1 ? fullCmd_.size() - 1 : 0;
181         for (size_t cmdSize = dataLen; i < cmdSize; i++) {
182             cmd.append(fullCmd_[i]).append(" ");
183         }
184         cmd.append(fullCmd_[i]);
185     }
186     return cmd;
187 }
188 
InitHisyseventCmd()189 inline bool HisyseventPlugin::InitHisyseventCmd()
190 {
191     PROFILER_LOG_INFO(LOG_CORE, "BEGN %s: ready!", __func__);
192     if (!fullCmd_.empty()) {
193         PROFILER_LOG_INFO(LOG_CORE, "fullCmd_ is dirty.Then clear().");
194         fullCmd_.clear();
195     }
196 
197     fullCmd_.emplace_back("/system/bin/hisysevent"); // exe file path
198     fullCmd_.emplace_back("hisysevent"); // exe file name
199     fullCmd_.emplace_back("-rd");
200 
201     if (!protoConfig_.subscribe_domain().empty()) {
202         fullCmd_.emplace_back("-o");
203         fullCmd_.emplace_back(protoConfig_.subscribe_domain());
204     }
205     if (!protoConfig_.subscribe_event().empty()) {
206         fullCmd_.emplace_back("-n");
207         fullCmd_.emplace_back(protoConfig_.subscribe_event());
208     }
209     PROFILER_LOG_INFO(LOG_CORE, "END %s: success!", __func__);
210     return true;
211 }
212 
213 template <typename T>
ParseSyseventLineInfo(const char * data,size_t len,T hisyseventInfoProto)214 inline bool HisyseventPlugin::ParseSyseventLineInfo(const char* data, size_t len, T hisyseventInfoProto)
215 {
216     CHECK_TRUE(data != nullptr && len >= MIN_STRING_LEN, false, "NOTE %s: param invalid", __func__);
217     size_t dataLen = strlen(data) > 1 ? strlen(data) - 1 : 0;
218     if (google::protobuf::internal::IsStructurallyValidUTF8(data, dataLen)) {
219         auto* info = hisyseventInfoProto->add_info();
220         info->set_id(id_);
221         size_t len = strlen(data) > 1 ? strlen(data) - 1 : 0;
222         info->set_context(data, len); // - \n
223         id_++;
224     } else {
225         PROFILER_LOG_ERROR(LOG_CORE, "NOTE HisyseventPlugin: hisysevent context include invalid UTF-8 data");
226         return false;
227     }
228     return true;
229 }
230 
WriteResult(const T hisyseventInfoProto)231 template <typename T> inline bool HisyseventPlugin::WriteResult(const T hisyseventInfoProto)
232 {
233     // Cmd result resize and SerializeToArray and after save to protoBuffer_ ;Then write and flush;Then clear_info
234     protoBuffer_.resize(hisyseventInfoProto->ByteSizeLong());
235     hisyseventInfoProto->SerializeToArray(protoBuffer_.data(), protoBuffer_.size());
236     // SerializeToArray after data=%s",protoBuffer_.data()
237     resultWriter_->write(resultWriter_, protoBuffer_.data(), protoBuffer_.size());
238     resultWriter_->flush(resultWriter_);
239     return true;
240 }
241 
FlushDataOptimize(const T hisyseventInfoProto)242 template <typename T> void HisyseventPlugin::FlushDataOptimize(const T hisyseventInfoProto)
243 {
244     int messageLen = hisyseventInfoProto->Finish();
245     resultWriter_->finishReport(resultWriter_, messageLen);
246     resultWriter_->flush(resultWriter_);
247 }
248