12f0d0f1aSopenharmony_ci/*
22f0d0f1aSopenharmony_ci* Copyright (c) 2024 Huawei Device Co., Ltd.
32f0d0f1aSopenharmony_ci* Licensed under the Apache License, Version 2.0 (the "License");
42f0d0f1aSopenharmony_ci* you may not use this file except in compliance with the License.
52f0d0f1aSopenharmony_ci* You may obtain a copy of the License at
62f0d0f1aSopenharmony_ci*
72f0d0f1aSopenharmony_ci*     http://www.apache.org/licenses/LICENSE-2.0
82f0d0f1aSopenharmony_ci*
92f0d0f1aSopenharmony_ci* Unless required by applicable law or agreed to in writing, software
102f0d0f1aSopenharmony_ci* distributed under the License is distributed on an "AS IS" BASIS,
112f0d0f1aSopenharmony_ci* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
122f0d0f1aSopenharmony_ci* See the License for the specific language governing permissions and
132f0d0f1aSopenharmony_ci* limitations under the License.
142f0d0f1aSopenharmony_ci*/
152f0d0f1aSopenharmony_ci
162f0d0f1aSopenharmony_ci#include <iostream>
172f0d0f1aSopenharmony_ci#include <fstream>
182f0d0f1aSopenharmony_ci#include <sstream>
192f0d0f1aSopenharmony_ci#include <algorithm>
202f0d0f1aSopenharmony_ci#include <cstdlib>
212f0d0f1aSopenharmony_ci#include <climits>
222f0d0f1aSopenharmony_ci#include <unordered_map>
232f0d0f1aSopenharmony_ci#include <functional>
242f0d0f1aSopenharmony_ci#include <mutex>
252f0d0f1aSopenharmony_ci#include "app_event.h"
262f0d0f1aSopenharmony_ci#include "app_event_processor_mgr.h"
272f0d0f1aSopenharmony_ci#include "drm_log.h"
282f0d0f1aSopenharmony_ci#include "drm_error_code.h"
292f0d0f1aSopenharmony_ci#include "drm_api_operation.h"
302f0d0f1aSopenharmony_ci
312f0d0f1aSopenharmony_cinamespace OHOS {
322f0d0f1aSopenharmony_cinamespace DrmStandard {
332f0d0f1aSopenharmony_ci// Global variables for caching file content and mutex
342f0d0f1aSopenharmony_cistd::string ConfigParser::g_fileContent = "";
352f0d0f1aSopenharmony_ciint64_t ConfigParser::g_processorId = -1;
362f0d0f1aSopenharmony_cistd::mutex ConfigParser::g_apiOperationMutex;
372f0d0f1aSopenharmony_ciconst int32_t APP_FLAG = -200;
382f0d0f1aSopenharmony_ci
392f0d0f1aSopenharmony_cibool ConfigParser::LoadConfigurationFile(const std::string &configFile)
402f0d0f1aSopenharmony_ci{
412f0d0f1aSopenharmony_ci    std::ifstream file(configFile);
422f0d0f1aSopenharmony_ci    if (!file.is_open()) {
432f0d0f1aSopenharmony_ci        perror("Unable to open api operation config file!");
442f0d0f1aSopenharmony_ci        return false;
452f0d0f1aSopenharmony_ci    }
462f0d0f1aSopenharmony_ci
472f0d0f1aSopenharmony_ci    std::ostringstream oss;
482f0d0f1aSopenharmony_ci    std::string line;
492f0d0f1aSopenharmony_ci    while (std::getline(file, line)) {
502f0d0f1aSopenharmony_ci        line = Trim(line);
512f0d0f1aSopenharmony_ci        if (!line.empty() && line[0] != '#') {
522f0d0f1aSopenharmony_ci            oss << line << "\n";
532f0d0f1aSopenharmony_ci        }
542f0d0f1aSopenharmony_ci    }
552f0d0f1aSopenharmony_ci    g_fileContent = oss.str();
562f0d0f1aSopenharmony_ci    file.close();
572f0d0f1aSopenharmony_ci    return true;
582f0d0f1aSopenharmony_ci}
592f0d0f1aSopenharmony_ci
602f0d0f1aSopenharmony_civoid ConfigParser::GetConfigurationParams(ApiReportConfig &reportConfig, ApiEventConfig &eventConfig)
612f0d0f1aSopenharmony_ci{
622f0d0f1aSopenharmony_ci    std::istringstream stream(g_fileContent);
632f0d0f1aSopenharmony_ci    ParseApiOperationManagement(stream, reportConfig, eventConfig);
642f0d0f1aSopenharmony_ci}
652f0d0f1aSopenharmony_ci
662f0d0f1aSopenharmony_cistd::string ConfigParser::Trim(const std::string &str)
672f0d0f1aSopenharmony_ci{
682f0d0f1aSopenharmony_ci    const char* whitespace = " \t\n\r";
692f0d0f1aSopenharmony_ci    size_t first = str.find_first_not_of(whitespace);
702f0d0f1aSopenharmony_ci    size_t last = str.find_last_not_of(whitespace);
712f0d0f1aSopenharmony_ci    return (first == std::string::npos) ? "" : str.substr(first, last - first + 1);
722f0d0f1aSopenharmony_ci}
732f0d0f1aSopenharmony_ci
742f0d0f1aSopenharmony_cistd::pair<std::string, std::string> ConfigParser::ParseKeyValue(const std::string &line)
752f0d0f1aSopenharmony_ci{
762f0d0f1aSopenharmony_ci    size_t colonPos = line.find(':');
772f0d0f1aSopenharmony_ci    if (colonPos != std::string::npos) {
782f0d0f1aSopenharmony_ci        std::string key = Trim(line.substr(0, colonPos));
792f0d0f1aSopenharmony_ci        std::string value = Trim(line.substr(colonPos + 1));
802f0d0f1aSopenharmony_ci        key.erase(std::remove(key.begin(), key.end(), '"'), key.end());
812f0d0f1aSopenharmony_ci        value.erase(std::remove(value.begin(), value.end(), '"'), value.end());
822f0d0f1aSopenharmony_ci        if (!value.empty() && value.back() == ',') {
832f0d0f1aSopenharmony_ci            value.pop_back(); // Remove trailing comma if present
842f0d0f1aSopenharmony_ci        }
852f0d0f1aSopenharmony_ci        return std::make_pair(key, value);
862f0d0f1aSopenharmony_ci    }
872f0d0f1aSopenharmony_ci    return std::make_pair("", "");
882f0d0f1aSopenharmony_ci}
892f0d0f1aSopenharmony_ci
902f0d0f1aSopenharmony_cibool ConfigParser::TryParseInt(const std::string& str, int& out)
912f0d0f1aSopenharmony_ci{
922f0d0f1aSopenharmony_ci    char* end;
932f0d0f1aSopenharmony_ci    long val = strtol(str.c_str(), &end, 10);
942f0d0f1aSopenharmony_ci    if (*end == '\0' && end != str.c_str() && val >= INT_MIN && val <= INT_MAX) {
952f0d0f1aSopenharmony_ci        out = static_cast<int>(val);
962f0d0f1aSopenharmony_ci        return true;
972f0d0f1aSopenharmony_ci    } else {
982f0d0f1aSopenharmony_ci        DRM_ERR_LOG("Invalid integer: %{public}s", str.c_str());
992f0d0f1aSopenharmony_ci        return false;
1002f0d0f1aSopenharmony_ci    }
1012f0d0f1aSopenharmony_ci}
1022f0d0f1aSopenharmony_ci
1032f0d0f1aSopenharmony_civoid ConfigParser::ParseReportConfig(std::istringstream &stream, ApiReportConfig &reportConfig)
1042f0d0f1aSopenharmony_ci{
1052f0d0f1aSopenharmony_ci    std::unordered_map<std::string, std::function<void(const std::string&)>> configMap = {
1062f0d0f1aSopenharmony_ci        {"config_name", [&](const std::string &value) { reportConfig.config_name = value; }},
1072f0d0f1aSopenharmony_ci        {"config_appId", [&](const std::string &value) { reportConfig.config_appId = value; }},
1082f0d0f1aSopenharmony_ci        {"config_routeInfo", [&](const std::string &value) { reportConfig.config_routeInfo = value; }},
1092f0d0f1aSopenharmony_ci        {"config_TriggerCond.timeout", [&](const std::string &value) {
1102f0d0f1aSopenharmony_ci            int temp;
1112f0d0f1aSopenharmony_ci            if (TryParseInt(value, temp)) {
1122f0d0f1aSopenharmony_ci                reportConfig.config_timeout = temp;
1132f0d0f1aSopenharmony_ci            } else {
1142f0d0f1aSopenharmony_ci                DRM_ERR_LOG("Invalid integer for config_timeout: %{public}s", value.c_str());
1152f0d0f1aSopenharmony_ci            }
1162f0d0f1aSopenharmony_ci        }},
1172f0d0f1aSopenharmony_ci        {"config_TriggerCond.row", [&](const std::string &value) {
1182f0d0f1aSopenharmony_ci            int temp;
1192f0d0f1aSopenharmony_ci            if (TryParseInt(value, temp)) {
1202f0d0f1aSopenharmony_ci                reportConfig.config_row = temp;
1212f0d0f1aSopenharmony_ci            } else {
1222f0d0f1aSopenharmony_ci                DRM_ERR_LOG("Invalid integer for config_row: %{public}s", value.c_str());
1232f0d0f1aSopenharmony_ci            }
1242f0d0f1aSopenharmony_ci        }}
1252f0d0f1aSopenharmony_ci    };
1262f0d0f1aSopenharmony_ci
1272f0d0f1aSopenharmony_ci    std::string line;
1282f0d0f1aSopenharmony_ci    while (std::getline(stream, line)) {
1292f0d0f1aSopenharmony_ci        line = Trim(line);
1302f0d0f1aSopenharmony_ci        if (line == "},") {
1312f0d0f1aSopenharmony_ci            break;
1322f0d0f1aSopenharmony_ci        }
1332f0d0f1aSopenharmony_ci        auto keyValue = ParseKeyValue(line);
1342f0d0f1aSopenharmony_ci        auto it = configMap.find(keyValue.first);
1352f0d0f1aSopenharmony_ci        if (it != configMap.end()) {
1362f0d0f1aSopenharmony_ci            it->second(keyValue.second);
1372f0d0f1aSopenharmony_ci        }
1382f0d0f1aSopenharmony_ci    }
1392f0d0f1aSopenharmony_ci}
1402f0d0f1aSopenharmony_ci
1412f0d0f1aSopenharmony_civoid ConfigParser::ParseEvent(std::istringstream &stream, ApiEvent &event)
1422f0d0f1aSopenharmony_ci{
1432f0d0f1aSopenharmony_ci    std::unordered_map<std::string, std::function<void(const std::string&)>> eventMap = {
1442f0d0f1aSopenharmony_ci        {"domain", [&](const std::string &value) { event.domain = value; }},
1452f0d0f1aSopenharmony_ci        {"name", [&](const std::string &value) { event.name = value; }},
1462f0d0f1aSopenharmony_ci        {"isRealTime", [&](const std::string &value) { event.isRealTime = (value == "true"); }}
1472f0d0f1aSopenharmony_ci    };
1482f0d0f1aSopenharmony_ci
1492f0d0f1aSopenharmony_ci    std::string line;
1502f0d0f1aSopenharmony_ci    while (std::getline(stream, line)) {
1512f0d0f1aSopenharmony_ci        line = Trim(line);
1522f0d0f1aSopenharmony_ci        if (line == "},") {
1532f0d0f1aSopenharmony_ci            break;
1542f0d0f1aSopenharmony_ci        }
1552f0d0f1aSopenharmony_ci        auto keyValue = ParseKeyValue(line);
1562f0d0f1aSopenharmony_ci        auto it = eventMap.find(keyValue.first);
1572f0d0f1aSopenharmony_ci        if (it != eventMap.end()) {
1582f0d0f1aSopenharmony_ci            it->second(keyValue.second);
1592f0d0f1aSopenharmony_ci        }
1602f0d0f1aSopenharmony_ci    }
1612f0d0f1aSopenharmony_ci}
1622f0d0f1aSopenharmony_ci
1632f0d0f1aSopenharmony_civoid ConfigParser::ParseEventConfig(std::istringstream &stream, ApiEventConfig &eventConfig)
1642f0d0f1aSopenharmony_ci{
1652f0d0f1aSopenharmony_ci    std::unordered_map<std::string, std::function<void(std::istringstream&)>> eventConfigMap = {
1662f0d0f1aSopenharmony_ci        {"\"event1\": {", [&](std::istringstream &stream) { ParseEvent(stream, eventConfig.event1); }},
1672f0d0f1aSopenharmony_ci        {"\"event2\": {", [&](std::istringstream &stream) { ParseEvent(stream, eventConfig.event2); }},
1682f0d0f1aSopenharmony_ci        {"\"event3\": {", [&](std::istringstream &stream) { ParseEvent(stream, eventConfig.event3); }}
1692f0d0f1aSopenharmony_ci    };
1702f0d0f1aSopenharmony_ci
1712f0d0f1aSopenharmony_ci    std::string line;
1722f0d0f1aSopenharmony_ci    while (std::getline(stream, line)) {
1732f0d0f1aSopenharmony_ci        line = Trim(line);
1742f0d0f1aSopenharmony_ci        if (line == "},") {
1752f0d0f1aSopenharmony_ci            break;
1762f0d0f1aSopenharmony_ci        }
1772f0d0f1aSopenharmony_ci        auto it = eventConfigMap.find(line);
1782f0d0f1aSopenharmony_ci        if (it != eventConfigMap.end()) {
1792f0d0f1aSopenharmony_ci            it->second(stream);
1802f0d0f1aSopenharmony_ci        }
1812f0d0f1aSopenharmony_ci    }
1822f0d0f1aSopenharmony_ci}
1832f0d0f1aSopenharmony_ci
1842f0d0f1aSopenharmony_civoid ConfigParser::ParseApiOperationManagement(std::istringstream &stream, ApiReportConfig &reportConfig,
1852f0d0f1aSopenharmony_ci    ApiEventConfig &eventConfig)
1862f0d0f1aSopenharmony_ci{
1872f0d0f1aSopenharmony_ci    std::unordered_map<std::string, std::function<void(std::istringstream&)>> apiOpMgmtMap = {
1882f0d0f1aSopenharmony_ci        {"\"report_config\": {", [&](std::istringstream &stream) { ParseReportConfig(stream, reportConfig); }},
1892f0d0f1aSopenharmony_ci        {"\"event_config\": {", [&](std::istringstream &stream) { ParseEventConfig(stream, eventConfig); }}
1902f0d0f1aSopenharmony_ci    };
1912f0d0f1aSopenharmony_ci
1922f0d0f1aSopenharmony_ci    std::string line;
1932f0d0f1aSopenharmony_ci    while (std::getline(stream, line)) {
1942f0d0f1aSopenharmony_ci        line = Trim(line);
1952f0d0f1aSopenharmony_ci        if (line == "}") {
1962f0d0f1aSopenharmony_ci            break;
1972f0d0f1aSopenharmony_ci        }
1982f0d0f1aSopenharmony_ci        auto it = apiOpMgmtMap.find(line);
1992f0d0f1aSopenharmony_ci        if (it != apiOpMgmtMap.end()) {
2002f0d0f1aSopenharmony_ci            it->second(stream);
2012f0d0f1aSopenharmony_ci        }
2022f0d0f1aSopenharmony_ci    }
2032f0d0f1aSopenharmony_ci}
2042f0d0f1aSopenharmony_ci
2052f0d0f1aSopenharmony_ciint64_t ConfigParser::AddProcessor()
2062f0d0f1aSopenharmony_ci{
2072f0d0f1aSopenharmony_ci    DRM_INFO_LOG("AddProcessor enter.");
2082f0d0f1aSopenharmony_ci    ApiReportConfig reportConfig;
2092f0d0f1aSopenharmony_ci    ApiEventConfig eventConfig;
2102f0d0f1aSopenharmony_ci    std::lock_guard<std::mutex> lock(g_apiOperationMutex);
2112f0d0f1aSopenharmony_ci    if (g_processorId != -1) {
2122f0d0f1aSopenharmony_ci        DRM_DEBUG_LOG("AddProcessor exit");
2132f0d0f1aSopenharmony_ci        return g_processorId;
2142f0d0f1aSopenharmony_ci    }
2152f0d0f1aSopenharmony_ci    if (g_processorId == APP_FLAG) {
2162f0d0f1aSopenharmony_ci        DRM_ERR_LOG("dotting is not supported for non-apps");
2172f0d0f1aSopenharmony_ci        return g_processorId;
2182f0d0f1aSopenharmony_ci    }
2192f0d0f1aSopenharmony_ci    if (LoadConfigurationFile(DRM_API_OPERATION_CONFIG_PATH) != true) {
2202f0d0f1aSopenharmony_ci        DRM_ERR_LOG("AddProcessor LoadConfigurationFile error!");
2212f0d0f1aSopenharmony_ci        return DRM_OPERATION_NOT_ALLOWED;
2222f0d0f1aSopenharmony_ci    }
2232f0d0f1aSopenharmony_ci    GetConfigurationParams(reportConfig, eventConfig);
2242f0d0f1aSopenharmony_ci    HiviewDFX::HiAppEvent::ReportConfig config;
2252f0d0f1aSopenharmony_ci    config.name = reportConfig.config_name;
2262f0d0f1aSopenharmony_ci    config.appId = reportConfig.config_appId;
2272f0d0f1aSopenharmony_ci    config.routeInfo = reportConfig.config_routeInfo;
2282f0d0f1aSopenharmony_ci    config.triggerCond.timeout = reportConfig.config_timeout;
2292f0d0f1aSopenharmony_ci    config.triggerCond.row = reportConfig.config_row;
2302f0d0f1aSopenharmony_ci    config.eventConfigs.clear();
2312f0d0f1aSopenharmony_ci    HiviewDFX::HiAppEvent::EventConfig event1;
2322f0d0f1aSopenharmony_ci    event1.domain = eventConfig.event1.domain;
2332f0d0f1aSopenharmony_ci    event1.name = eventConfig.event1.name;
2342f0d0f1aSopenharmony_ci    event1.isRealTime = eventConfig.event1.isRealTime;
2352f0d0f1aSopenharmony_ci    config.eventConfigs.push_back(event1);
2362f0d0f1aSopenharmony_ci    HiviewDFX::HiAppEvent::EventConfig event2;
2372f0d0f1aSopenharmony_ci    event2.domain = eventConfig.event2.domain;
2382f0d0f1aSopenharmony_ci    event2.name = eventConfig.event2.name;
2392f0d0f1aSopenharmony_ci    event2.isRealTime = eventConfig.event2.isRealTime;
2402f0d0f1aSopenharmony_ci    config.eventConfigs.push_back(event2);
2412f0d0f1aSopenharmony_ci    HiviewDFX::HiAppEvent::EventConfig event3;
2422f0d0f1aSopenharmony_ci    event3.domain = eventConfig.event3.domain;
2432f0d0f1aSopenharmony_ci    event3.name = eventConfig.event3.name;
2442f0d0f1aSopenharmony_ci    event3.isRealTime = eventConfig.event3.isRealTime;
2452f0d0f1aSopenharmony_ci    config.eventConfigs.push_back(event3);
2462f0d0f1aSopenharmony_ci    g_processorId = HiviewDFX::HiAppEvent::AppEventProcessorMgr::AddProcessor(config);
2472f0d0f1aSopenharmony_ci    return g_processorId;
2482f0d0f1aSopenharmony_ci}
2492f0d0f1aSopenharmony_ci
2502f0d0f1aSopenharmony_civoid ConfigParser::WriteEndEvent(const int result, const int errCode, std::string apiName, int64_t beginTime)
2512f0d0f1aSopenharmony_ci{
2522f0d0f1aSopenharmony_ci    DRM_INFO_LOG("WriteEndEvent enter.");
2532f0d0f1aSopenharmony_ci    (void)AddProcessor();
2542f0d0f1aSopenharmony_ci    std::string transId = std::string("traceId_") + std::to_string(std::rand());
2552f0d0f1aSopenharmony_ci    int64_t endTime = std::chrono::duration_cast<std::chrono::milliseconds>(
2562f0d0f1aSopenharmony_ci        std::chrono::system_clock::now().time_since_epoch()).count();
2572f0d0f1aSopenharmony_ci
2582f0d0f1aSopenharmony_ci    HiviewDFX::HiAppEvent::Event event("api_diagnostic", "api_exec_end", OHOS::HiviewDFX::HiAppEvent::BEHAVIOR);
2592f0d0f1aSopenharmony_ci    event.AddParam("trans_id", transId);
2602f0d0f1aSopenharmony_ci    event.AddParam("api_name", apiName);
2612f0d0f1aSopenharmony_ci    event.AddParam("sdk_name", std::string("DrmKit"));
2622f0d0f1aSopenharmony_ci    event.AddParam("begin_time", beginTime);
2632f0d0f1aSopenharmony_ci    event.AddParam("end_time", endTime);
2642f0d0f1aSopenharmony_ci    event.AddParam("result", result);
2652f0d0f1aSopenharmony_ci    event.AddParam("error_code", errCode);
2662f0d0f1aSopenharmony_ci    HiviewDFX::HiAppEvent::Write(event);
2672f0d0f1aSopenharmony_ci}
2682f0d0f1aSopenharmony_ci}  // namespace DrmStandard
2692f0d0f1aSopenharmony_ci}  // namespace OHOS