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 "export_json_file_writer.h"
17
18 #include <chrono>
19 #include <cstdio>
20 #include <tuple>
21 #include <sstream>
22
23 #include "file_util.h"
24 #include "focused_event_util.h"
25 #include "hiview_global.h"
26 #include "hiview_logger.h"
27 #include "hiview_zip_util.h"
28 #include "parameter.h"
29 #include "parameter_ex.h"
30 #include "string_util.h"
31 #include "time_util.h"
32
33 namespace OHOS {
34 namespace HiviewDFX {
35 DEFINE_LOG_TAG("HiView-ExportJsonFileWriter");
36 namespace {
37 constexpr int64_t MB_TO_BYTE = 1024 * 1024;
38 constexpr int64_t INVALID_EVENT_SEQ = -1;
39 constexpr char SYSEVENT_EXPORT_TMP_DIR[] = "tmp";
40 constexpr char SYSEVENT_EXPORT_DIR[] = "sys_event_export";
41 constexpr char EXPORT_JSON_FILE_NAME[] = "HiSysEvent.json";
42 constexpr char SYS_EVENT_EXPORT_DIR_NAME[] = "sys_event_export";
43 constexpr char ZIP_FILE_DELIM[] = "_";
44 constexpr char CUR_HEADER_VERSION[] = "1.0";
45 constexpr char H_HEADER_KEY[] = "HEADER";
46 constexpr char H_VERSION_KEY[] = "VERSION";
47 constexpr char H_MSG_ID_KEY[] = "MESSAGE_ID";
48 constexpr char H_MANUFACTURE_KEY[] = "MANUFACTURER";
49 constexpr char H_NAME_KEY[] = "NAME";
50 constexpr char H_BRAND_KEY[] = "BRAND";
51 constexpr char H_DEVICE_KEY[] = "DEVICE";
52 constexpr char H_ID_KEY[] = "ID";
53 constexpr char H_MODEL_KEY[] = "MODEL";
54 constexpr char H_CATEGORY_KEY[] = "CATEGORY";
55 constexpr char H_SYSTEM_KEY[] = "SYSTEM";
56 constexpr char H_OHOS_VER_KEY[] = "OHOS_VER";
57 constexpr char H_PATCH_VER_KEY[] = "PATCH_VER";
58 constexpr char DOMAINS_KEY[] = "DOMAINS";
59 constexpr char DOMAIN_INFO_KEY[] = "DOMAIN_INFO";
60 constexpr char EVENTS_KEY[] = "EVENTS";
61 constexpr char DATA_KEY[] = "DATA";
62 constexpr char DEFAULT_MSG_ID[] = "00000000000000000000000000000000";
63 constexpr mode_t EVENT_EXPORT_DIR_MODE = S_IRWXU | S_IROTH | S_IWOTH | S_IXOTH; // rwx---rwx
64 constexpr mode_t EVENT_EXPORT_FILE_MODE = S_IRUSR | S_IWUSR | S_IROTH | S_IWOTH; // rw----rw-
65
GenerateDeviceId()66 std::string GenerateDeviceId()
67 {
68 constexpr int32_t deviceIdLength = 65;
69 char id[deviceIdLength] = {0};
70 if (GetDevUdid(id, deviceIdLength) == 0) {
71 return std::string(id);
72 }
73 return "";
74 }
75
GetDeviceId()76 std::string GetDeviceId()
77 {
78 static std::string deviceId = GenerateDeviceId();
79 return deviceId;
80 }
81
CreateHeaderJsonObj()82 cJSON* CreateHeaderJsonObj()
83 {
84 cJSON* header = cJSON_CreateObject();
85 if (header == nullptr) {
86 HIVIEW_LOGE("failed to create header json object");
87 return nullptr;
88 }
89 cJSON_AddStringToObject(header, H_VERSION_KEY, CUR_HEADER_VERSION);
90 cJSON_AddStringToObject(header, H_MSG_ID_KEY, DEFAULT_MSG_ID);
91 return header;
92 }
93
CreateManufacturerJsonObj()94 cJSON* CreateManufacturerJsonObj()
95 {
96 cJSON* manufacturer = cJSON_CreateObject();
97 if (manufacturer == nullptr) {
98 HIVIEW_LOGE("failed to create manufacturer json object");
99 return nullptr;
100 }
101 cJSON_AddStringToObject(manufacturer, H_NAME_KEY, Parameter::GetManufactureStr().c_str());
102 cJSON_AddStringToObject(manufacturer, H_BRAND_KEY, Parameter::GetBrandStr().c_str());
103 return manufacturer;
104 }
105
CreateDeviceJsonObj()106 cJSON* CreateDeviceJsonObj()
107 {
108 cJSON* device = cJSON_CreateObject();
109 if (device == nullptr) {
110 HIVIEW_LOGE("failed to create device json object");
111 return nullptr;
112 }
113 cJSON_AddStringToObject(device, H_ID_KEY, GetDeviceId().c_str());
114 cJSON_AddStringToObject(device, H_MODEL_KEY, Parameter::GetProductModelStr().c_str());
115 cJSON_AddStringToObject(device, H_NAME_KEY, Parameter::GetMarketNameStr().c_str());
116 cJSON_AddStringToObject(device, H_CATEGORY_KEY, Parameter::GetDeviceTypeStr().c_str());
117 return device;
118 }
119
CreateSystemObj(const EventVersion & eventVersion)120 cJSON* CreateSystemObj(const EventVersion& eventVersion)
121 {
122 cJSON* system = cJSON_CreateObject();
123 if (system == nullptr) {
124 HIVIEW_LOGE("failed to create system json object");
125 return nullptr;
126 }
127 cJSON_AddStringToObject(system, H_VERSION_KEY, eventVersion.systemVersion.c_str());
128 cJSON_AddStringToObject(system, H_OHOS_VER_KEY, Parameter::GetSysVersionDetailsStr().c_str());
129 cJSON_AddStringToObject(system, H_PATCH_VER_KEY, eventVersion.patchVersion.c_str());
130 return system;
131 }
132
CreateJsonObjectByVersion(const EventVersion & eventVersion)133 cJSON* CreateJsonObjectByVersion(const EventVersion& eventVersion)
134 {
135 cJSON* root = cJSON_CreateObject();
136 if (root == nullptr) {
137 HIVIEW_LOGE("failed to create root json object");
138 return nullptr;
139 }
140 // add header
141 auto headerObj = CreateHeaderJsonObj();
142 if (headerObj != nullptr) {
143 cJSON_AddItemToObjectCS(root, H_HEADER_KEY, headerObj);
144 }
145 // add manufacturer
146 auto manufacturerObj = CreateManufacturerJsonObj();
147 if (manufacturerObj != nullptr) {
148 cJSON_AddItemToObjectCS(root, H_MANUFACTURE_KEY, manufacturerObj);
149 }
150 auto deviceObj = CreateDeviceJsonObj();
151 if (deviceObj != nullptr) {
152 cJSON_AddItemToObjectCS(root, H_DEVICE_KEY, deviceObj);
153 }
154 auto systemObj = CreateSystemObj(eventVersion);
155 if (systemObj != nullptr) {
156 cJSON_AddItemToObjectCS(root, H_SYSTEM_KEY, systemObj);
157 }
158 return root;
159 }
160
CreateEventsJsonArray(const std::string & domain,const std::vector<std::pair<std::string,std::string>> & events)161 cJSON* CreateEventsJsonArray(const std::string& domain,
162 const std::vector<std::pair<std::string, std::string>>& events)
163 {
164 // events
165 cJSON* eventsJsonArray = cJSON_CreateArray();
166 if (eventsJsonArray == nullptr) {
167 HIVIEW_LOGE("failed to create events json array");
168 return nullptr;
169 }
170 cJSON* dataJsonArray = cJSON_CreateArray();
171 if (dataJsonArray == nullptr) {
172 HIVIEW_LOGE("failed to create data json array");
173 return nullptr;
174 }
175 for (const auto& event : events) {
176 cJSON* eventItem = cJSON_Parse(event.second.c_str());
177 if (FocusedEventUtil::IsFocusedEvent(domain, event.first)) {
178 HIVIEW_LOGI("write event to json: [%{public}s|%{public}s]", domain.c_str(),
179 event.first.c_str());
180 }
181 cJSON_AddItemToArray(dataJsonArray, eventItem);
182 }
183 cJSON* anonymousJsonObj = cJSON_CreateObject();
184 if (anonymousJsonObj == nullptr) {
185 HIVIEW_LOGE("failed to create anonymousJsonObj json object");
186 return nullptr;
187 }
188 cJSON_AddItemToObjectCS(anonymousJsonObj, DATA_KEY, dataJsonArray);
189 cJSON_AddItemToArray(eventsJsonArray, anonymousJsonObj);
190 return eventsJsonArray;
191 }
192
GetHiSysEventJsonTempDir(const std::string & moduleName,const EventVersion & version)193 std::string GetHiSysEventJsonTempDir(const std::string& moduleName, const EventVersion& version)
194 {
195 auto& context = HiviewGlobal::GetInstance();
196 if (context == nullptr) {
197 return "";
198 }
199 std::string tmpDir = context->GetHiViewDirectory(HiviewContext::DirectoryType::WORK_DIRECTORY);
200 tmpDir = FileUtil::IncludeTrailingPathDelimiter(tmpDir.append(SYSEVENT_EXPORT_DIR));
201 tmpDir = FileUtil::IncludeTrailingPathDelimiter(tmpDir.append(SYSEVENT_EXPORT_TMP_DIR));
202 tmpDir = FileUtil::IncludeTrailingPathDelimiter(tmpDir.append(moduleName));
203 tmpDir = FileUtil::IncludeTrailingPathDelimiter(tmpDir.append(version.systemVersion));
204 if (!FileUtil::IsDirectory(tmpDir) && !FileUtil::ForceCreateDirectory(tmpDir)) {
205 HIVIEW_LOGE("failed to init directory %{public}s.", tmpDir.c_str());
206 return "";
207 }
208 return tmpDir;
209 }
210
ZipDbFile(const std::string & src,const std::string & dest)211 bool ZipDbFile(const std::string& src, const std::string& dest)
212 {
213 HiviewZipUnit zipUnit(dest);
214 if (int32_t ret = zipUnit.AddFileInZip(src, ZipFileLevel::KEEP_NONE_PARENT_PATH); ret != 0) {
215 HIVIEW_LOGW("zip db failed, ret: %{public}d.", ret);
216 return false;
217 }
218 if (bool ret = FileUtil::ChangeModeFile(dest, EVENT_EXPORT_FILE_MODE); !ret) {
219 HIVIEW_LOGE("failed to chmod file %{public}s.", StringUtil::HideDeviceIdInfo(dest).c_str());
220 return false;
221 }
222 // delete json file
223 FileUtil::RemoveFile(src);
224 return true;
225 }
226
AppendZipFile(std::string & dir)227 void AppendZipFile(std::string& dir)
228 {
229 dir.append("HSE").append(ZIP_FILE_DELIM)
230 .append(Parameter::GetBrandStr()).append(std::string(ZIP_FILE_DELIM))
231 .append(Parameter::GetProductModelStr()).append(std::string(ZIP_FILE_DELIM))
232 .append(Parameter::GetSysVersionStr()).append(std::string(ZIP_FILE_DELIM))
233 .append(GetDeviceId()).append(std::string(ZIP_FILE_DELIM))
234 .append(TimeUtil::GetFormattedTimestampEndWithMilli()).append(std::string(".zip"));
235 }
236
GetTmpZipFile(const std::string & baseDir,const std::string & moduleName,const EventVersion & version)237 std::string GetTmpZipFile(const std::string& baseDir, const std::string& moduleName,
238 const EventVersion& version)
239 {
240 std::string dir = FileUtil::IncludeTrailingPathDelimiter(baseDir);
241 dir = FileUtil::IncludeTrailingPathDelimiter(dir.append(SYSEVENT_EXPORT_TMP_DIR));
242 dir = FileUtil::IncludeTrailingPathDelimiter(dir.append(moduleName));
243 dir = FileUtil::IncludeTrailingPathDelimiter(dir.append(version.systemVersion));
244 if (!FileUtil::IsDirectory(dir) && !FileUtil::ForceCreateDirectory(dir)) {
245 HIVIEW_LOGE("failed to init directory %{public}s.", dir.c_str());
246 return "";
247 }
248 AppendZipFile(dir);
249 return dir;
250 }
251
GetZipFile(const std::string & baseDir)252 std::string GetZipFile(const std::string& baseDir)
253 {
254 std::string dir = FileUtil::IncludeTrailingPathDelimiter(baseDir);
255 dir = FileUtil::IncludeTrailingPathDelimiter(dir.append(SYS_EVENT_EXPORT_DIR_NAME));
256 if (!FileUtil::IsDirectory(dir) && !FileUtil::ForceCreateDirectory(dir)) {
257 HIVIEW_LOGE("failed to init directory %{public}s.", dir.c_str());
258 return "";
259 }
260 if (!FileUtil::ChangeModeFile(dir, EVENT_EXPORT_DIR_MODE)) {
261 HIVIEW_LOGE("failed to change file mode of %{public}s.", dir.c_str());
262 return "";
263 }
264 AppendZipFile(dir);
265 return dir;
266 }
267
PersistJsonStrToLocalFile(cJSON * root,const std::string & localFile)268 void PersistJsonStrToLocalFile(cJSON* root, const std::string& localFile)
269 {
270 if (root == nullptr) {
271 HIVIEW_LOGE("root of json is null");
272 return;
273 }
274 char* parsedJsonStr = cJSON_PrintUnformatted(root);
275 if (parsedJsonStr == nullptr) {
276 HIVIEW_LOGE("formatted json str is null");
277 return;
278 }
279 FILE* file = fopen(localFile.c_str(), "w+");
280 if (file == nullptr) {
281 HIVIEW_LOGE("failed to open file: %{public}s.", localFile.c_str());
282 cJSON_free(parsedJsonStr);
283 return;
284 }
285 (void)fprintf(file, "%s", parsedJsonStr);
286 (void)fclose(file);
287 cJSON_free(parsedJsonStr);
288 }
289 }
290
Write()291 bool ExportJsonFileWriter::Write()
292 {
293 cJSON* root = CreateJsonObjectByVersion(eventVersion_);
294 if (root == nullptr) {
295 return false;
296 }
297 cJSON* domainsJsonArray = cJSON_CreateArray();
298 if (domainsJsonArray == nullptr) {
299 HIVIEW_LOGE("failed to create json array");
300 cJSON_Delete(root);
301 return false;
302 }
303 for (const auto& sysEvent : sysEventMap_) {
304 cJSON* domainJsonObj = cJSON_CreateObject();
305 if (domainJsonObj == nullptr) {
306 continue;
307 }
308 // domain info
309 cJSON* domainInfoJsonObj = cJSON_CreateObject();
310 if (domainInfoJsonObj == nullptr) {
311 HIVIEW_LOGE("failed to create domain info json object");
312 continue;
313 }
314 cJSON_AddStringToObject(domainInfoJsonObj, H_NAME_KEY, sysEvent.first.c_str());
315 cJSON_AddItemToObjectCS(domainJsonObj, DOMAIN_INFO_KEY, domainInfoJsonObj);
316 cJSON* eventsJsonObj = CreateEventsJsonArray(sysEvent.first, sysEvent.second);
317 if (eventsJsonObj == nullptr) {
318 continue;
319 }
320 cJSON_AddItemToObjectCS(domainJsonObj, EVENTS_KEY, eventsJsonObj);
321 cJSON_AddItemToArray(domainsJsonArray, domainJsonObj);
322 }
323 // add domains
324 cJSON_AddItemToObjectCS(root, DOMAINS_KEY, domainsJsonArray);
325 // create export json file HiSysEvent.json
326 auto packagedFile = GetHiSysEventJsonTempDir(moduleName_, eventVersion_).append(EXPORT_JSON_FILE_NAME);
327 HIVIEW_LOGD("packagedFile: %{public}s", packagedFile.c_str());
328 PersistJsonStrToLocalFile(root, packagedFile);
329 cJSON_Delete(root);
330 // zip json file into a temporary zip file
331 auto tmpZipFile = GetTmpZipFile(exportDir_, moduleName_, eventVersion_);
332 if (!ZipDbFile(packagedFile, tmpZipFile)) {
333 HIVIEW_LOGE("failed to zip %{public}s to %{public}s", packagedFile.c_str(),
334 StringUtil::HideDeviceIdInfo(tmpZipFile).c_str());
335 return false;
336 }
337 auto zipFile = GetZipFile(exportDir_);
338 HIVIEW_LOGD("zipFile: %{public}s", StringUtil::HideDeviceIdInfo(zipFile).c_str());
339 if (exportJsonFileZippedListener_ != nullptr) {
340 exportJsonFileZippedListener_(tmpZipFile, zipFile);
341 }
342 totalJsonStrSize_ = 0;
343 sysEventMap_.clear(); // clear cache;
344 return true;
345 }
346
ExportJsonFileWriter(const std::string & moduleName,const EventVersion & eventVersion,const std::string & exportDir,int64_t maxFileSize)347 ExportJsonFileWriter::ExportJsonFileWriter(const std::string& moduleName, const EventVersion& eventVersion,
348 const std::string& exportDir, int64_t maxFileSize)
349 {
350 moduleName_ = moduleName;
351 eventVersion_ = eventVersion;
352 exportDir_ = exportDir;
353 maxFileSize_ = maxFileSize * MB_TO_BYTE;
354 }
355
SetExportJsonFileZippedListener(ExportJsonFileZippedListener listener)356 void ExportJsonFileWriter::SetExportJsonFileZippedListener(ExportJsonFileZippedListener listener)
357 {
358 exportJsonFileZippedListener_ = listener;
359 }
360
AppendEvent(const std::string & domain,const std::string & name,const std::string & eventStr)361 bool ExportJsonFileWriter::AppendEvent(const std::string& domain, const std::string& name,
362 const std::string& eventStr)
363 {
364 int64_t eventSize = static_cast<int64_t>(eventStr.size());
365 if (totalJsonStrSize_ + eventSize > maxFileSize_ && !Write()) {
366 HIVIEW_LOGE("failed to write export events");
367 return false;
368 }
369 auto iter = sysEventMap_.find(domain);
370 if (iter == sysEventMap_.end()) {
371 sysEventMap_.emplace(domain, std::vector<std::pair<std::string, std::string>> {
372 std::make_pair(name, eventStr),
373 });
374 totalJsonStrSize_ += eventSize;
375 return true;
376 }
377 iter->second.emplace_back(name, eventStr);
378 totalJsonStrSize_ += eventSize;
379 return true;
380 }
381
ClearEventCache()382 void ExportJsonFileWriter::ClearEventCache()
383 {
384 sysEventMap_.clear();
385 }
386 } // HiviewDFX
387 } // OHOS