1/*
2 * Copyright (c) 2023 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 "decoded/decoded_event.h"
17
18#include <functional>
19#include <securec.h>
20#include <sstream>
21#include <unordered_map>
22
23#include "base/raw_data_base_def.h"
24#include "decoded/raw_data_decoder.h"
25#include "hiview_logger.h"
26
27namespace OHOS {
28namespace HiviewDFX {
29namespace EventRaw {
30DEFINE_LOG_TAG("HiView-DecodedEvent");
31namespace {
32constexpr size_t MAX_BLOCK_SIZE = 384 * 1024; // 384K
33constexpr size_t MAX_PARAM_CNT = 128 + 10; // 128 for Write, 10 for hiview
34
35std::string TransUInt64ToFixedLengthStr(uint64_t src)
36{
37    const size_t maxIdLen = 20;
38    std::string uint64Str = std::to_string(src);
39    if (uint64Str.size() >= maxIdLen) {
40        return uint64Str;
41    }
42    std::string dest(maxIdLen, '0');
43    dest.replace(maxIdLen - uint64Str.size(), uint64Str.size(), uint64Str);
44    return dest;
45}
46}
47
48DecodedEvent::DecodedEvent(uint8_t* src)
49{
50    if (src == nullptr) {
51        return;
52    }
53    size_t blockSize = static_cast<size_t>(*(reinterpret_cast<int32_t*>(src)));
54    if (blockSize < GetValidDataMinimumByteCount() || blockSize > MAX_BLOCK_SIZE) {
55        HIVIEW_LOGE("size of raw data is %{public}zu, which is invalid.", blockSize);
56        return;
57    }
58    rawData_ = new(std::nothrow) uint8_t[blockSize];
59    if (rawData_ == nullptr) {
60        return;
61    }
62    auto ret = memcpy_s(rawData_, blockSize, src, blockSize);
63    if (ret != EOK) {
64        HIVIEW_LOGE("Decode memory copy failed, ret is %{public}d.", ret);
65        delete[] rawData_;
66        return;
67    }
68    Parse();
69}
70
71DecodedEvent::~DecodedEvent()
72{
73    if (rawData_ != nullptr) {
74        delete[] rawData_;
75        rawData_ = nullptr;
76    }
77}
78
79void DecodedEvent::AppendBaseInfo(std::stringstream& ss)
80{
81    char* domain = new(std::nothrow) char[MAX_DOMAIN_LENGTH + 1];
82    if (domain == nullptr) {
83        return;
84    }
85    if (memcpy_s(domain, MAX_DOMAIN_LENGTH, header_.domain, MAX_DOMAIN_LENGTH) != EOK) {
86        delete[] domain;
87        return;
88    }
89    domain[MAX_DOMAIN_LENGTH] = '\0';
90    auto eventDomain = std::string(domain);
91    AppendValue(ss, BASE_INFO_KEY_DOMAIN, eventDomain);
92    delete[] domain;
93    char* name = new(std::nothrow) char[MAX_EVENT_NAME_LENGTH + 1];
94    if (name == nullptr) {
95        return;
96    }
97    if (memcpy_s(name, MAX_EVENT_NAME_LENGTH, header_.name, MAX_EVENT_NAME_LENGTH) != EOK) {
98        delete[] name;
99        return;
100    }
101    name[MAX_EVENT_NAME_LENGTH] = '\0';
102    auto eventName = std::string(name);
103    AppendValue(ss, BASE_INFO_KEY_NAME, eventName);
104    delete[] name;
105    AppendValue(ss, BASE_INFO_KEY_TYPE, (static_cast<int>(header_.type) + 1)); // header_.type is only 2 bits which has
106                                                                          // been subtracted 1 before wrote.
107    AppendValue(ss, BASE_INFO_KEY_TIME_STAMP, header_.timestamp);
108    auto timeZone = ParseTimeZone(static_cast<size_t>(header_.timeZone));
109    AppendValue(ss, BASE_INFO_KEY_TIME_ZONE, timeZone);
110    AppendValue(ss, BASE_INFO_KEY_PID, header_.pid);
111    AppendValue(ss, BASE_INFO_KEY_TID, header_.tid);
112    AppendValue(ss, BASE_INFO_KEY_UID, header_.uid);
113    AppendValue(ss, BASE_INFO_KEY_LOG, static_cast<uint32_t>(header_.log));
114    AppendValue(ss, BASE_INFO_KEY_ID, TransUInt64ToFixedLengthStr(header_.id));
115    if (header_.isTraceOpened == 1) {
116        AppendValue(ss, BASE_INFO_KEY_TRACE_FLAG, static_cast<int>(traceInfo_.traceFlag));
117        AppendValue(ss, BASE_INFO_KEY_TRACE_ID, TransNumToHexStr(traceInfo_.traceId));
118        AppendValue(ss, BASE_INFO_KEY_SPAN_ID, TransNumToHexStr(traceInfo_.spanId));
119        AppendValue(ss, BASE_INFO_KEY_PARENT_SPAN_ID, TransNumToHexStr(traceInfo_.pSpanId));
120    }
121}
122
123void DecodedEvent::AppendCustomizedArrayParam(std::stringstream& ss, std::shared_ptr<DecodedParam> param)
124{
125    std::unordered_map<DataCodedType, std::function<void(std::shared_ptr<DecodedParam>)>> allFuncs = {
126        {DataCodedType::UNSIGNED_VARINT_ARRAY, [this, &ss](std::shared_ptr<DecodedParam> param) {
127                std::vector<uint64_t> u64Vec;
128                if (param->AsUint64Vec(u64Vec)) {
129                    this->AppendValue(ss, param->GetKey(), u64Vec);
130                }
131            }
132        },
133        {DataCodedType::SIGNED_VARINT_ARRAY, [this, &ss](std::shared_ptr<DecodedParam> param) {
134                std::vector<int64_t> i64Vec;
135                if (param->AsInt64Vec(i64Vec)) {
136                    this->AppendValue(ss, param->GetKey(), i64Vec);
137                }
138            }
139        },
140        {DataCodedType::FLOATING_ARRAY, [this, &ss](std::shared_ptr<DecodedParam> param) {
141                std::vector<double> dVec;
142                if (param->AsDoubleVec(dVec)) {
143                    this->AppendValue(ss, param->GetKey(), dVec);
144                }
145            }
146        },
147        {DataCodedType::DSTRING_ARRAY, [this, &ss](std::shared_ptr<DecodedParam> param) {
148                std::vector<std::string> strVec;
149                if (param->AsStringVec(strVec)) {
150                    this->AppendValue(ss, param->GetKey(), strVec);
151                }
152            }
153        }
154    };
155    auto iter = allFuncs.find(param->GetDataCodedType());
156    if (iter == allFuncs.end()) {
157        return;
158    }
159    iter->second(param);
160}
161
162void DecodedEvent::AppendCustomizedParam(std::stringstream& ss, std::shared_ptr<DecodedParam> param)
163{
164    std::unordered_map<DataCodedType, std::function<void(std::shared_ptr<DecodedParam>)>> allFuncs = {
165        {DataCodedType::UNSIGNED_VARINT, [this, &ss](std::shared_ptr<DecodedParam> param) {
166                uint64_t uint64DecodedVal;
167                if (param->AsUint64(uint64DecodedVal)) {
168                    this->AppendValue(ss, param->GetKey(), uint64DecodedVal);
169                }
170            }
171        },
172        {DataCodedType::SIGNED_VARINT, [this, &ss](std::shared_ptr<DecodedParam> param) {
173                int64_t int64DecodedVal;
174                if (param->AsInt64(int64DecodedVal)) {
175                    this->AppendValue(ss, param->GetKey(), int64DecodedVal);
176                }
177            }
178        },
179        {DataCodedType::FLOATING, [this, &ss](std::shared_ptr<DecodedParam> param) {
180                double dDecodedVal;
181                if (param->AsDouble(dDecodedVal)) {
182                    this->AppendValue(ss, param->GetKey(), dDecodedVal);
183                }
184            }
185        },
186        {DataCodedType::DSTRING, [this, &ss](std::shared_ptr<DecodedParam> param) {
187                std::string strDecodedVal;
188                if (param->AsString(strDecodedVal)) {
189                    this->AppendValue(ss, param->GetKey(), strDecodedVal);
190                }
191            }
192        }
193    };
194    auto iter = allFuncs.find(param->GetDataCodedType());
195    if (iter == allFuncs.end()) {
196        return;
197    }
198    iter->second(param);
199}
200
201void DecodedEvent::AppendCustomizedParams(std::stringstream& ss)
202{
203    for (auto param: allParams_) {
204        if (param == nullptr) {
205            continue;
206        }
207        std::vector<DataCodedType> noArrayEncodedTypes = {
208            DataCodedType::UNSIGNED_VARINT,
209            DataCodedType::SIGNED_VARINT,
210            DataCodedType::FLOATING,
211            DataCodedType::DSTRING,
212        };
213        if (find(noArrayEncodedTypes.begin(), noArrayEncodedTypes.end(), param->GetDataCodedType()) !=
214            noArrayEncodedTypes.end()) {
215            AppendCustomizedParam(ss, param);
216            continue;
217        }
218        AppendCustomizedArrayParam(ss, param);
219    }
220}
221
222std::string DecodedEvent::AsJsonStr()
223{
224    std::stringstream jsonStream;
225    jsonStream << "{";
226    AppendBaseInfo(jsonStream);
227    AppendCustomizedParams(jsonStream);
228    if (jsonStream.tellp() != 0) {
229        jsonStream.seekp(-1, std::ios_base::end);
230    }
231    jsonStream << "}";
232    return jsonStream.str();
233}
234
235std::shared_ptr<RawData> DecodedEvent::GetRawData()
236{
237    return std::make_shared<RawData>(rawData_, pos_);
238}
239
240bool DecodedEvent::IsValid()
241{
242    return isValid_;
243}
244
245const struct HiSysEventHeader& DecodedEvent::GetHeader()
246{
247    return header_;
248}
249
250const struct TraceInfo& DecodedEvent::GetTraceInfo()
251{
252    return traceInfo_;
253}
254
255const std::vector<std::shared_ptr<DecodedParam>>& DecodedEvent::GetAllCustomizedValues()
256{
257    return allParams_;
258}
259
260void DecodedEvent::Parse()
261{
262    isValid_ = true;
263    if (rawData_ == nullptr) {
264        isValid_ = false;
265        return;
266    }
267    pos_ = 0; // reset to 0
268    // decode block size
269    size_t blockSize = static_cast<size_t>(*(reinterpret_cast<int32_t*>(rawData_)));
270    pos_ += sizeof(int32_t);
271    ParseHeader(blockSize);
272    ParseCustomizedParams(blockSize);
273}
274
275void DecodedEvent::ParseHeader(const size_t maxLen)
276{
277    // decode event header
278    if ((pos_ + sizeof(struct HiSysEventHeader)) > maxLen) {
279        isValid_ = false;
280        return;
281    }
282    header_ = *(reinterpret_cast<struct HiSysEventHeader*>(rawData_ + pos_));
283    pos_ += sizeof(struct HiSysEventHeader);
284    // decode trace info
285    if (header_.isTraceOpened == 1) { // 1: include trace info, 0: exclude trace info
286        if (((pos_ + sizeof(struct TraceInfo)) > maxLen)) {
287            isValid_ = false;
288            return;
289        }
290        traceInfo_ = *(reinterpret_cast<struct TraceInfo*>(rawData_ + pos_));
291        pos_ += sizeof(struct TraceInfo);
292    }
293}
294
295void DecodedEvent::ParseCustomizedParams(const size_t maxLen)
296{
297    if ((pos_ + sizeof(int32_t)) > maxLen) {
298        isValid_ = false;
299        return;
300    }
301    auto paramCnt = static_cast<size_t>(*(reinterpret_cast<int32_t*>(rawData_ + pos_)));
302    if (paramCnt > MAX_PARAM_CNT) {
303        HIVIEW_LOGW("invalid param cnt=%{public}zu.", paramCnt);
304        isValid_ = false;
305        return;
306    }
307    pos_ += sizeof(int32_t);
308    while (paramCnt > 0) {
309        auto decodedParam = ParseCustomizedParam(maxLen);
310        if (decodedParam == nullptr || !(decodedParam->DecodeValue())) {
311            HIVIEW_LOGE("Value of customized parameter is decoded failed.");
312            isValid_ = false;
313            return;
314        }
315        pos_ = decodedParam->GetPosition();
316        allParams_.emplace_back(decodedParam);
317        --paramCnt;
318    }
319}
320
321std::shared_ptr<DecodedParam> DecodedEvent::CreateFloatingNumTypeDecodedParam(const size_t maxLen,
322    const std::string& key, bool isArray)
323{
324    if (isArray) {
325        return std::make_shared<FloatingNumberDecodedArrayParam>(rawData_, maxLen, pos_, key);
326    }
327    return std::make_shared<FloatingNumberDecodedParam>(rawData_, maxLen, pos_, key);
328}
329
330std::shared_ptr<DecodedParam> DecodedEvent::CreateSignedVarintTypeDecodedParam(const size_t maxLen,
331    const std::string& key, bool isArray)
332{
333    if (isArray) {
334        return std::make_shared<SignedVarintDecodedArrayParam>(rawData_, maxLen, pos_, key);
335    }
336    return std::make_shared<SignedVarintDecodedParam>(rawData_, maxLen, pos_, key);
337}
338
339std::shared_ptr<DecodedParam> DecodedEvent::CreateStringTypeDecodedParam(const size_t maxLen,
340    const std::string& key, bool isArray)
341{
342    if (isArray) {
343        return std::make_shared<StringDecodedArrayParam>(rawData_, maxLen, pos_, key);
344    }
345    return std::make_shared<StringDecodedParam>(rawData_, maxLen, pos_, key);
346}
347
348std::shared_ptr<DecodedParam> DecodedEvent::CreateUnsignedVarintTypeDecodedParam(const size_t maxLen,
349    const std::string& key, bool isArray)
350{
351    if (isArray) {
352        return std::make_shared<UnsignedVarintDecodedArrayParam>(rawData_, maxLen, pos_, key);
353    }
354    return std::make_shared<UnsignedVarintDecodedParam>(rawData_, maxLen, pos_, key);
355}
356
357std::shared_ptr<DecodedParam> DecodedEvent::ParseCustomizedParam(const size_t maxLen)
358{
359    std::string key;
360    if (!RawDataDecoder::StringValueDecoded(rawData_, maxLen, pos_, key)) {
361        isValid_ = false;
362        return nullptr;
363    }
364    struct ParamValueType valueType {
365        .isArray = 0,
366        .valueType = static_cast<uint8_t>(ValueType::UNKNOWN),
367        .valueByteCnt = 0,
368    };
369    if (!RawDataDecoder::ValueTypeDecoded(rawData_, maxLen, pos_, valueType)) {
370        isValid_ = false;
371        return nullptr;
372    }
373    std::shared_ptr<DecodedParam> ret = nullptr;
374    switch (ValueType(valueType.valueType)) {
375        case ValueType::STRING: {
376            ret = CreateStringTypeDecodedParam(maxLen, key, valueType.isArray == 1);
377            break;
378        }
379        case ValueType::FLOAT:
380        case ValueType::DOUBLE: {
381            ret = CreateFloatingNumTypeDecodedParam(maxLen, key, valueType.isArray == 1);
382            break;
383        }
384        case ValueType::UINT8:
385        case ValueType::UINT16:
386        case ValueType::UINT32:
387        case ValueType::UINT64: {
388            ret = CreateUnsignedVarintTypeDecodedParam(maxLen, key, valueType.isArray == 1);
389            break;
390        }
391        case ValueType::BOOL:
392        case ValueType::INT8:
393        case ValueType::INT16:
394        case ValueType::INT32:
395        case ValueType::INT64: {
396            ret = CreateSignedVarintTypeDecodedParam(maxLen, key, valueType.isArray == 1);
397            break;
398        }
399        default:
400            break;
401    }
402    return ret;
403}
404} // namespace EventRaw
405} // namespace HiviewDFX
406} // namespace OHOS