1 /*
2 * Copyright (c) 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 <iostream>
17 #include <fstream>
18 #include <sstream>
19 #include <algorithm>
20 #include <cstdlib>
21 #include <climits>
22 #include <unordered_map>
23 #include <functional>
24 #include <mutex>
25 #include "app_event.h"
26 #include "app_event_processor_mgr.h"
27 #include "drm_log.h"
28 #include "drm_error_code.h"
29 #include "drm_api_operation.h"
30
31 namespace OHOS {
32 namespace DrmStandard {
33 // Global variables for caching file content and mutex
34 std::string ConfigParser::g_fileContent = "";
35 int64_t ConfigParser::g_processorId = -1;
36 std::mutex ConfigParser::g_apiOperationMutex;
37 const int32_t APP_FLAG = -200;
38
LoadConfigurationFile(const std::string & configFile)39 bool ConfigParser::LoadConfigurationFile(const std::string &configFile)
40 {
41 std::ifstream file(configFile);
42 if (!file.is_open()) {
43 perror("Unable to open api operation config file!");
44 return false;
45 }
46
47 std::ostringstream oss;
48 std::string line;
49 while (std::getline(file, line)) {
50 line = Trim(line);
51 if (!line.empty() && line[0] != '#') {
52 oss << line << "\n";
53 }
54 }
55 g_fileContent = oss.str();
56 file.close();
57 return true;
58 }
59
GetConfigurationParams(ApiReportConfig & reportConfig,ApiEventConfig & eventConfig)60 void ConfigParser::GetConfigurationParams(ApiReportConfig &reportConfig, ApiEventConfig &eventConfig)
61 {
62 std::istringstream stream(g_fileContent);
63 ParseApiOperationManagement(stream, reportConfig, eventConfig);
64 }
65
Trim(const std::string & str)66 std::string ConfigParser::Trim(const std::string &str)
67 {
68 const char* whitespace = " \t\n\r";
69 size_t first = str.find_first_not_of(whitespace);
70 size_t last = str.find_last_not_of(whitespace);
71 return (first == std::string::npos) ? "" : str.substr(first, last - first + 1);
72 }
73
ParseKeyValue(const std::string & line)74 std::pair<std::string, std::string> ConfigParser::ParseKeyValue(const std::string &line)
75 {
76 size_t colonPos = line.find(':');
77 if (colonPos != std::string::npos) {
78 std::string key = Trim(line.substr(0, colonPos));
79 std::string value = Trim(line.substr(colonPos + 1));
80 key.erase(std::remove(key.begin(), key.end(), '"'), key.end());
81 value.erase(std::remove(value.begin(), value.end(), '"'), value.end());
82 if (!value.empty() && value.back() == ',') {
83 value.pop_back(); // Remove trailing comma if present
84 }
85 return std::make_pair(key, value);
86 }
87 return std::make_pair("", "");
88 }
89
TryParseInt(const std::string & str,int & out)90 bool ConfigParser::TryParseInt(const std::string& str, int& out)
91 {
92 char* end;
93 long val = strtol(str.c_str(), &end, 10);
94 if (*end == '\0' && end != str.c_str() && val >= INT_MIN && val <= INT_MAX) {
95 out = static_cast<int>(val);
96 return true;
97 } else {
98 DRM_ERR_LOG("Invalid integer: %{public}s", str.c_str());
99 return false;
100 }
101 }
102
ParseReportConfig(std::istringstream & stream,ApiReportConfig & reportConfig)103 void ConfigParser::ParseReportConfig(std::istringstream &stream, ApiReportConfig &reportConfig)
104 {
105 std::unordered_map<std::string, std::function<void(const std::string&)>> configMap = {
106 {"config_name", [&](const std::string &value) { reportConfig.config_name = value; }},
107 {"config_appId", [&](const std::string &value) { reportConfig.config_appId = value; }},
108 {"config_routeInfo", [&](const std::string &value) { reportConfig.config_routeInfo = value; }},
109 {"config_TriggerCond.timeout", [&](const std::string &value) {
110 int temp;
111 if (TryParseInt(value, temp)) {
112 reportConfig.config_timeout = temp;
113 } else {
114 DRM_ERR_LOG("Invalid integer for config_timeout: %{public}s", value.c_str());
115 }
116 }},
117 {"config_TriggerCond.row", [&](const std::string &value) {
118 int temp;
119 if (TryParseInt(value, temp)) {
120 reportConfig.config_row = temp;
121 } else {
122 DRM_ERR_LOG("Invalid integer for config_row: %{public}s", value.c_str());
123 }
124 }}
125 };
126
127 std::string line;
128 while (std::getline(stream, line)) {
129 line = Trim(line);
130 if (line == "},") {
131 break;
132 }
133 auto keyValue = ParseKeyValue(line);
134 auto it = configMap.find(keyValue.first);
135 if (it != configMap.end()) {
136 it->second(keyValue.second);
137 }
138 }
139 }
140
ParseEvent(std::istringstream & stream,ApiEvent & event)141 void ConfigParser::ParseEvent(std::istringstream &stream, ApiEvent &event)
142 {
143 std::unordered_map<std::string, std::function<void(const std::string&)>> eventMap = {
144 {"domain", [&](const std::string &value) { event.domain = value; }},
145 {"name", [&](const std::string &value) { event.name = value; }},
146 {"isRealTime", [&](const std::string &value) { event.isRealTime = (value == "true"); }}
147 };
148
149 std::string line;
150 while (std::getline(stream, line)) {
151 line = Trim(line);
152 if (line == "},") {
153 break;
154 }
155 auto keyValue = ParseKeyValue(line);
156 auto it = eventMap.find(keyValue.first);
157 if (it != eventMap.end()) {
158 it->second(keyValue.second);
159 }
160 }
161 }
162
ParseEventConfig(std::istringstream & stream,ApiEventConfig & eventConfig)163 void ConfigParser::ParseEventConfig(std::istringstream &stream, ApiEventConfig &eventConfig)
164 {
165 std::unordered_map<std::string, std::function<void(std::istringstream&)>> eventConfigMap = {
166 {"\"event1\": {", [&](std::istringstream &stream) { ParseEvent(stream, eventConfig.event1); }},
167 {"\"event2\": {", [&](std::istringstream &stream) { ParseEvent(stream, eventConfig.event2); }},
168 {"\"event3\": {", [&](std::istringstream &stream) { ParseEvent(stream, eventConfig.event3); }}
169 };
170
171 std::string line;
172 while (std::getline(stream, line)) {
173 line = Trim(line);
174 if (line == "},") {
175 break;
176 }
177 auto it = eventConfigMap.find(line);
178 if (it != eventConfigMap.end()) {
179 it->second(stream);
180 }
181 }
182 }
183
ParseApiOperationManagement(std::istringstream & stream,ApiReportConfig & reportConfig,ApiEventConfig & eventConfig)184 void ConfigParser::ParseApiOperationManagement(std::istringstream &stream, ApiReportConfig &reportConfig,
185 ApiEventConfig &eventConfig)
186 {
187 std::unordered_map<std::string, std::function<void(std::istringstream&)>> apiOpMgmtMap = {
188 {"\"report_config\": {", [&](std::istringstream &stream) { ParseReportConfig(stream, reportConfig); }},
189 {"\"event_config\": {", [&](std::istringstream &stream) { ParseEventConfig(stream, eventConfig); }}
190 };
191
192 std::string line;
193 while (std::getline(stream, line)) {
194 line = Trim(line);
195 if (line == "}") {
196 break;
197 }
198 auto it = apiOpMgmtMap.find(line);
199 if (it != apiOpMgmtMap.end()) {
200 it->second(stream);
201 }
202 }
203 }
204
AddProcessor()205 int64_t ConfigParser::AddProcessor()
206 {
207 DRM_INFO_LOG("AddProcessor enter.");
208 ApiReportConfig reportConfig;
209 ApiEventConfig eventConfig;
210 std::lock_guard<std::mutex> lock(g_apiOperationMutex);
211 if (g_processorId != -1) {
212 DRM_DEBUG_LOG("AddProcessor exit");
213 return g_processorId;
214 }
215 if (g_processorId == APP_FLAG) {
216 DRM_ERR_LOG("dotting is not supported for non-apps");
217 return g_processorId;
218 }
219 if (LoadConfigurationFile(DRM_API_OPERATION_CONFIG_PATH) != true) {
220 DRM_ERR_LOG("AddProcessor LoadConfigurationFile error!");
221 return DRM_OPERATION_NOT_ALLOWED;
222 }
223 GetConfigurationParams(reportConfig, eventConfig);
224 HiviewDFX::HiAppEvent::ReportConfig config;
225 config.name = reportConfig.config_name;
226 config.appId = reportConfig.config_appId;
227 config.routeInfo = reportConfig.config_routeInfo;
228 config.triggerCond.timeout = reportConfig.config_timeout;
229 config.triggerCond.row = reportConfig.config_row;
230 config.eventConfigs.clear();
231 HiviewDFX::HiAppEvent::EventConfig event1;
232 event1.domain = eventConfig.event1.domain;
233 event1.name = eventConfig.event1.name;
234 event1.isRealTime = eventConfig.event1.isRealTime;
235 config.eventConfigs.push_back(event1);
236 HiviewDFX::HiAppEvent::EventConfig event2;
237 event2.domain = eventConfig.event2.domain;
238 event2.name = eventConfig.event2.name;
239 event2.isRealTime = eventConfig.event2.isRealTime;
240 config.eventConfigs.push_back(event2);
241 HiviewDFX::HiAppEvent::EventConfig event3;
242 event3.domain = eventConfig.event3.domain;
243 event3.name = eventConfig.event3.name;
244 event3.isRealTime = eventConfig.event3.isRealTime;
245 config.eventConfigs.push_back(event3);
246 g_processorId = HiviewDFX::HiAppEvent::AppEventProcessorMgr::AddProcessor(config);
247 return g_processorId;
248 }
249
WriteEndEvent(const int result,const int errCode,std::string apiName,int64_t beginTime)250 void ConfigParser::WriteEndEvent(const int result, const int errCode, std::string apiName, int64_t beginTime)
251 {
252 DRM_INFO_LOG("WriteEndEvent enter.");
253 (void)AddProcessor();
254 std::string transId = std::string("traceId_") + std::to_string(std::rand());
255 int64_t endTime = std::chrono::duration_cast<std::chrono::milliseconds>(
256 std::chrono::system_clock::now().time_since_epoch()).count();
257
258 HiviewDFX::HiAppEvent::Event event("api_diagnostic", "api_exec_end", OHOS::HiviewDFX::HiAppEvent::BEHAVIOR);
259 event.AddParam("trans_id", transId);
260 event.AddParam("api_name", apiName);
261 event.AddParam("sdk_name", std::string("DrmKit"));
262 event.AddParam("begin_time", beginTime);
263 event.AddParam("end_time", endTime);
264 event.AddParam("result", result);
265 event.AddParam("error_code", errCode);
266 HiviewDFX::HiAppEvent::Write(event);
267 }
268 } // namespace DrmStandard
269 } // namespace OHOS