1 /*
2  * Copyright (c) 2023-2024 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 
16 #include "encoded/raw_data_builder.h"
17 
18 #include <cinttypes>
19 #include <securec.h>
20 #include <sstream>
21 #include <vector>
22 
23 #include "decoded/decoded_event.h"
24 #include "hiview_logger.h"
25 
26 namespace OHOS {
27 namespace HiviewDFX {
28 namespace EventRaw {
29 DEFINE_LOG_TAG("HiView-RawDataBuilder");
RawDataBuilder(std::shared_ptr<EventRaw::RawData> rawData)30 RawDataBuilder::RawDataBuilder(std::shared_ptr<EventRaw::RawData> rawData)
31 {
32     if (rawData == nullptr) {
33         return;
34     }
35     EventRaw::DecodedEvent event(rawData->GetData());
36     auto header = event.GetHeader();
37     auto traceInfo = event.GetTraceInfo();
38     AppendDomain(header.domain).AppendName(header.name).AppendType(static_cast<int>(header.type) + 1).
39         AppendTimeStamp(header.timestamp).AppendTimeZone(header.timeZone).AppendLog(header.log).
40         AppendUid(header.uid).AppendPid(header.pid).AppendTid(header.tid).AppendId(header.id);
41     if (header.isTraceOpened == 1) {
42         AppendTraceInfo(traceInfo.traceId, traceInfo.spanId, traceInfo.pSpanId, traceInfo.traceFlag);
43     }
44     InitValueParams(event.GetAllCustomizedValues());
45 }
46 
RawDataBuilder(const std::string & domain,const std::string & name,const int eventType)47 RawDataBuilder::RawDataBuilder(const std::string& domain, const std::string& name, const int eventType)
48 {
49     (void)AppendDomain(domain);
50     (void)AppendName(name);
51     (void)AppendType(eventType);
52 }
53 
BuildHeader(std::shared_ptr<RawData> dest)54 bool RawDataBuilder::BuildHeader(std::shared_ptr<RawData> dest)
55 {
56     if (!dest->Append(reinterpret_cast<uint8_t*>(&header_), sizeof(struct HiSysEventHeader))) {
57         HIVIEW_LOGE("Event header copy failed.");
58         return false;
59     }
60     // append trace info
61     if (header_.isTraceOpened == 1 &&
62         !dest->Append(reinterpret_cast<uint8_t*>(&traceInfo_), sizeof(struct TraceInfo))) {
63         HIVIEW_LOGE("Trace info copy failed.");
64         return false;
65     }
66     return true;
67 }
68 
BuildCustomizedParams(std::shared_ptr<RawData> dest)69 bool RawDataBuilder::BuildCustomizedParams(std::shared_ptr<RawData> dest)
70 {
71     std::lock_guard<std::mutex> lock(paramsOptMtx_);
72     return !any_of(allParams_.begin(), allParams_.end(), [&dest] (auto& param) {
73         auto rawData = param->GetRawData();
74         return !dest->Append(rawData.GetData(), rawData.GetDataLength());
75     });
76 }
77 
Build()78 std::shared_ptr<RawData> RawDataBuilder::Build()
79 {
80     // placehold block size
81     int32_t blockSize = 0;
82     auto rawData = std::make_shared<RawData>();
83     if (!rawData->Append(reinterpret_cast<uint8_t*>(&blockSize), sizeof(int32_t))) {
84         HIVIEW_LOGE("Block size copy failed.");
85         return nullptr;
86     }
87     if (!BuildHeader(rawData)) {
88         HIVIEW_LOGE("Header of sysevent build failed.");
89         return nullptr;
90     }
91     // append parameter count
92     int32_t paramCnt = static_cast<int32_t>(allParams_.size());
93     if (!rawData->Append(reinterpret_cast<uint8_t*>(&paramCnt), sizeof(int32_t))) {
94         HIVIEW_LOGE("Parameter count copy failed.");
95         return rawData;
96     }
97     if (!BuildCustomizedParams(rawData)) {
98         HIVIEW_LOGE("Customized paramters of sysevent build failed.");
99         return rawData;
100     }
101     // update block size
102     blockSize = static_cast<int32_t>(rawData->GetDataLength());
103     if (!rawData->Update(reinterpret_cast<uint8_t*>(&blockSize), sizeof(int32_t), 0)) {
104         HIVIEW_LOGE("Failed to update block size.");
105     }
106     return rawData;
107 }
108 
IsBaseInfo(const std::string & key)109 bool RawDataBuilder::IsBaseInfo(const std::string& key)
110 {
111     std::vector<const std::string> allBaseInfoKeys = {
112         BASE_INFO_KEY_DOMAIN, BASE_INFO_KEY_NAME, BASE_INFO_KEY_TYPE, BASE_INFO_KEY_TIME_STAMP, BASE_INFO_KEY_LOG,
113         BASE_INFO_KEY_TIME_ZONE, BASE_INFO_KEY_ID, BASE_INFO_KEY_PID, BASE_INFO_KEY_TID, BASE_INFO_KEY_UID,
114         BASE_INFO_KEY_TRACE_ID, BASE_INFO_KEY_SPAN_ID, BASE_INFO_KEY_PARENT_SPAN_ID, BASE_INFO_KEY_TRACE_FLAG
115     };
116     return find(allBaseInfoKeys.begin(), allBaseInfoKeys.end(), key) != allBaseInfoKeys.end();
117 }
118 
AppendDomain(const std::string & domain)119 RawDataBuilder& RawDataBuilder::AppendDomain(const std::string& domain)
120 {
121     auto ret = memcpy_s(header_.domain, MAX_DOMAIN_LENGTH, domain.c_str(), domain.length());
122     if (ret != EOK) {
123         HIVIEW_LOGE("Failed to copy event domain, ret is %{public}d.", ret);
124     }
125     auto resetPos = std::min(domain.length(), static_cast<size_t>(MAX_DOMAIN_LENGTH));
126     header_.domain[resetPos] = '\0';
127     return *this;
128 }
129 
AppendName(const std::string & name)130 RawDataBuilder& RawDataBuilder::AppendName(const std::string& name)
131 {
132     auto ret = memcpy_s(header_.name, MAX_EVENT_NAME_LENGTH, name.c_str(), name.length());
133     if (ret != EOK) {
134         HIVIEW_LOGE("Failed to copy event name, ret is %{public}d.", ret);
135     }
136     auto resetPos = std::min(name.length(), static_cast<size_t>(MAX_EVENT_NAME_LENGTH));
137     header_.name[resetPos] = '\0';
138     return *this;
139 }
140 
AppendType(const int eventType)141 RawDataBuilder& RawDataBuilder::AppendType(const int eventType)
142 {
143     header_.type = static_cast<uint8_t>(eventType - 1); // header_.type is only 2 bits which must be
144                                                        // subtracted 1 in order to avoid data overrflow.
145     return *this;
146 }
147 
AppendTimeStamp(const uint64_t timestamp)148 RawDataBuilder& RawDataBuilder::AppendTimeStamp(const uint64_t timestamp)
149 {
150     header_.timestamp = timestamp;
151     return *this;
152 }
153 
AppendTimeZone(const std::string & timeZone)154 RawDataBuilder& RawDataBuilder::AppendTimeZone(const std::string& timeZone)
155 {
156     header_.timeZone = static_cast<uint8_t>(ParseTimeZone(timeZone));
157     return *this;
158 }
159 
AppendTimeZone(const uint8_t timeZone)160 RawDataBuilder& RawDataBuilder::AppendTimeZone(const uint8_t timeZone)
161 {
162     header_.timeZone = timeZone;
163     return *this;
164 }
165 
AppendUid(const uint32_t uid)166 RawDataBuilder& RawDataBuilder::AppendUid(const uint32_t uid)
167 {
168     header_.uid = uid;
169     return *this;
170 }
171 
AppendPid(const uint32_t pid)172 RawDataBuilder& RawDataBuilder::AppendPid(const uint32_t pid)
173 {
174     header_.pid = pid;
175     return *this;
176 }
177 
AppendTid(const uint32_t tid)178 RawDataBuilder& RawDataBuilder::AppendTid(const uint32_t tid)
179 {
180     header_.tid = tid;
181     return *this;
182 }
183 
AppendLog(const uint8_t log)184 RawDataBuilder& RawDataBuilder::AppendLog(const uint8_t log)
185 {
186     header_.log = log;
187     return *this;
188 }
189 
AppendId(const uint64_t id)190 RawDataBuilder& RawDataBuilder::AppendId(const uint64_t id)
191 {
192     header_.id = id;
193     return *this;
194 }
195 
AppendId(const std::string & id)196 RawDataBuilder& RawDataBuilder::AppendId(const std::string& id)
197 {
198     uint64_t u64Id = 0;
199     std::stringstream ss(id);
200     ss >> u64Id;
201     AppendId(u64Id);
202     return *this;
203 }
204 
AppendTraceId(const uint64_t traceId)205 RawDataBuilder& RawDataBuilder::AppendTraceId(const uint64_t traceId)
206 {
207     header_.isTraceOpened = 1;
208     traceInfo_.traceId = traceId;
209     return *this;
210 }
211 
AppendSpanId(const uint32_t spanId)212 RawDataBuilder& RawDataBuilder::AppendSpanId(const uint32_t spanId)
213 {
214     header_.isTraceOpened = 1;
215     traceInfo_.spanId = spanId;
216     return *this;
217 }
218 
AppendPSpanId(const uint32_t pSpanId)219 RawDataBuilder& RawDataBuilder::AppendPSpanId(const uint32_t pSpanId)
220 {
221     header_.isTraceOpened = 1;
222     traceInfo_.pSpanId = pSpanId;
223     return *this;
224 }
225 
AppendTraceFlag(const uint8_t traceFlag)226 RawDataBuilder& RawDataBuilder::AppendTraceFlag(const uint8_t traceFlag)
227 {
228     header_.isTraceOpened = 1;
229     traceInfo_.traceFlag = traceFlag;
230     return *this;
231 }
232 
AppendTraceInfo(const uint64_t traceId,const uint32_t spanId,const uint32_t pSpanId,const uint8_t traceFlag)233 RawDataBuilder& RawDataBuilder::AppendTraceInfo(const uint64_t traceId, const uint32_t spanId,
234     const uint32_t pSpanId, const uint8_t traceFlag)
235 {
236     header_.isTraceOpened = 1; // 1: include trace info, 0: exclude trace info.
237 
238     traceInfo_.traceId = traceId;
239     traceInfo_.spanId = spanId;
240     traceInfo_.pSpanId = pSpanId;
241     traceInfo_.traceFlag = traceFlag;
242 
243     return *this;
244 }
245 
AppendValue(std::shared_ptr<EncodedParam> param)246 RawDataBuilder& RawDataBuilder::AppendValue(std::shared_ptr<EncodedParam> param)
247 {
248     if (param == nullptr || !param->Encode()) {
249         return *this;
250     }
251     auto paramKey = param->GetKey();
252     std::lock_guard<std::mutex> lock(paramsOptMtx_);
253     for (auto iter = allParams_.begin(); iter != allParams_.end(); ++iter) {
254         if ((*iter) == nullptr) {
255             continue;
256         }
257         if ((*iter)->GetKey() == paramKey) {
258             *iter = param;
259             return *this;
260         }
261     }
262     allParams_.emplace_back(param);
263     return *this;
264 }
265 
GetValue(const std::string & key)266 std::shared_ptr<EncodedParam> RawDataBuilder::GetValue(const std::string& key)
267 {
268     std::lock_guard<std::mutex> lock(paramsOptMtx_);
269     for (auto iter = allParams_.begin(); iter != allParams_.end(); ++iter) {
270         if ((*iter) == nullptr) {
271             continue;
272         }
273         if ((*iter)->GetKey() == key) {
274             return *iter;
275         }
276     }
277     return nullptr;
278 }
279 
GetDomain()280 std::string RawDataBuilder::GetDomain()
281 {
282     return std::string(header_.domain);
283 }
284 
GetName()285 std::string RawDataBuilder::GetName()
286 {
287     return std::string(header_.name);
288 }
289 
GetEventType()290 int RawDataBuilder::GetEventType()
291 {
292     return static_cast<int>(header_.type) + 1; // only 2 bits
293 }
294 
GetParamCnt()295 size_t RawDataBuilder::GetParamCnt()
296 {
297     return allParams_.size();
298 }
299 
GetHeader()300 struct HiSysEventHeader& RawDataBuilder::GetHeader()
301 {
302     return header_;
303 }
304 
GetTraceInfo()305 struct TraceInfo& RawDataBuilder::GetTraceInfo()
306 {
307     return traceInfo_;
308 }
309 
InitValueParams(const std::vector<std::shared_ptr<DecodedParam>> & params)310 void RawDataBuilder::InitValueParams(const std::vector<std::shared_ptr<DecodedParam>>& params)
311 {
312     std::unordered_map<EventRaw::DataCodedType,
313         std::function<void(std::shared_ptr<DecodedParam>)>> paramFuncs = {
314         {EventRaw::DataCodedType::UNSIGNED_VARINT, [this] (std::shared_ptr<DecodedParam> param) {
315                 if (uint64_t val = 0; param->AsUint64(val)) {
316                     this->AppendValue(std::make_shared<UnsignedVarintEncodedParam<uint64_t>>(param->GetKey(),
317                         val));
318                 }
319             }
320         },
321         {EventRaw::DataCodedType::SIGNED_VARINT, [this] (std::shared_ptr<DecodedParam> param) {
322                 if (int64_t val = 0; param->AsInt64(val)) {
323                     this->AppendValue(std::make_shared<SignedVarintEncodedParam<int64_t>>(param->GetKey(),
324                         val));
325                 }
326             }
327         },
328         {EventRaw::DataCodedType::FLOATING, [this] (std::shared_ptr<DecodedParam> param) {
329                 if (double val = 0.0; param->AsDouble(val)) {
330                     this->AppendValue(std::make_shared<FloatingNumberEncodedParam<double>>(param->GetKey(),
331                         val));
332                 }
333             }
334         },
335         {EventRaw::DataCodedType::DSTRING, [this] (std::shared_ptr<DecodedParam> param) {
336                 if (std::string val; param->AsString(val)) {
337                     this->AppendValue(std::make_shared<StringEncodedParam>(param->GetKey(),
338                         val));
339                 }
340             }
341         }
342     };
343     auto iter = paramFuncs.begin();
344     for (const auto& param : params) {
345         if (param == nullptr) {
346             continue;
347         }
348         iter = paramFuncs.find(param->GetDataCodedType());
349         if (iter == paramFuncs.end()) {
350             continue;
351         }
352         iter->second(param);
353     }
354     InitArrayValueParams(params);
355 }
356 
InitArrayValueParams(const std::vector<std::shared_ptr<DecodedParam>> & params)357 void RawDataBuilder::InitArrayValueParams(const std::vector<std::shared_ptr<DecodedParam>>& params)
358 {
359     std::unordered_map<EventRaw::DataCodedType,
360         std::function<void(std::shared_ptr<DecodedParam>)>> paramFuncs = {
361         {EventRaw::DataCodedType::UNSIGNED_VARINT_ARRAY, [this] (std::shared_ptr<DecodedParam> param) {
362                 if (std::vector<uint64_t> vals; param->AsUint64Vec(vals)) {
363                     this->AppendValue(std::make_shared<UnsignedVarintEncodedArrayParam<uint64_t>>(param->GetKey(),
364                         vals));
365                 }
366             }
367         },
368         {EventRaw::DataCodedType::SIGNED_VARINT_ARRAY, [this] (std::shared_ptr<DecodedParam> param) {
369                 if (std::vector<int64_t> vals; param->AsInt64Vec(vals)) {
370                     this->AppendValue(std::make_shared<SignedVarintEncodedArrayParam<int64_t>>(param->GetKey(),
371                         vals));
372                 }
373             }
374         },
375         {EventRaw::DataCodedType::FLOATING_ARRAY, [this] (std::shared_ptr<DecodedParam> param) {
376                 if (std::vector<double> vals; param->AsDoubleVec(vals)) {
377                     this->AppendValue(std::make_shared<FloatingNumberEncodedArrayParam<double>>(param->GetKey(),
378                         vals));
379                 }
380             }
381         },
382         {EventRaw::DataCodedType::DSTRING_ARRAY, [this] (std::shared_ptr<DecodedParam> param) {
383                 if (std::vector<std::string> vals; param->AsStringVec(vals)) {
384                     this->AppendValue(std::make_shared<StringEncodedArrayParam>(param->GetKey(),
385                         vals));
386                 }
387             }
388         }
389     };
390     auto iter = paramFuncs.begin();
391     for (const auto& param : params) {
392         if (param == nullptr) {
393             continue;
394         }
395         iter = paramFuncs.find(param->GetDataCodedType());
396         if (iter == paramFuncs.end()) {
397             continue;
398         }
399         iter->second(param);
400     }
401 }
402 } // namespace EventRaw
403 } // namespace HiviewDFX
404 } // namespace OHOS