1/* 2 * Copyright (c) 2022 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 "report.h" 17 18#include <algorithm> 19#include <dirent.h> 20#include <fstream> 21#include <iostream> 22#include <sstream> 23#include <sys/inotify.h> 24#include <sys/stat.h> 25#include <unistd.h> 26 27#include "ability_manager_client.h" 28#include "element_name.h" 29#include "exception_manager.h" 30#include "filter_category.h" 31#include "format_csv.h" 32#include "format_json.h" 33#include "statistics_ability.h" 34#include "statistics_componment.h" 35#include "statistics_event.h" 36#include "statistics_exception.h" 37#include "string_ex.h" 38#include "wukong_define.h" 39#include "wukong_util.h" 40 41namespace OHOS { 42namespace WuKong { 43namespace { 44const uint32_t SEGMENT_STATISTICS_LENGTH = 10; 45std::string crashDir = "/data/log/faultlog/faultlogger/"; 46void ListenCrashDir() 47{ 48 int fd; 49 int wd; 50 ssize_t readLenght; 51 char buf[BUFSIZ]; 52 char* bufPtr = nullptr; 53 struct inotify_event *event; 54 fd = inotify_init(); 55 INFO_LOG("init notify"); 56 if (fd < 0) { 57 return; 58 } 59 wd = inotify_add_watch(fd, "/data/log/faultlog/faultlogger/", IN_CLOSE_WRITE); 60 INFO_LOG("add_watch"); 61 if (wd < 0) { 62 ERROR_LOG("inotify_add_watch /data/log/faultlog/faultlogger/ failed"); 63 return; 64 } 65 buf[sizeof(buf) - 1] = 0; 66 std::string destDir = Report::GetInstance()->GetReportExceptionDir(); 67 while ((readLenght = read(fd, buf, sizeof(buf) - 1)) > 0) { 68 uint32_t len = static_cast<uint32_t>(readLenght); 69 uint32_t nread = 0; 70 while (len > 0) { 71 bufPtr = &buf[nread]; 72 void* middleType = static_cast<void *>(bufPtr); 73 event = static_cast<struct inotify_event *>(middleType); 74 if ((event->mask & IN_CLOSE_WRITE) && (event->len > 0)) { 75 DEBUG_LOG_STR("event->mask{%x}", event->mask); 76 std::string targetFile(event->name); 77 WuKongUtil::GetInstance()->CopyFile(targetFile, crashDir, destDir); 78 DEBUG_LOG_STR("%s --- IN_CLOSE_WRITE\n", event->name); 79 Report::GetInstance()->ExceptionRecord(targetFile); 80 } 81 nread = nread + sizeof(struct inotify_event) + event->len; 82 len = len - sizeof(struct inotify_event) - event->len; 83 } 84 } 85 INFO_LOG("exit thread"); 86 return; 87} 88 89void StartCrashDirListen() 90{ 91 std::thread listenerThread(&ListenCrashDir); 92 INFO_LOG("create listener thread"); 93 listenerThread.detach(); 94 INFO_LOG("thread detach"); 95} 96} // namespace 97using namespace OHOS::AAFwk; 98Report::Report() 99{ 100 EnvInit(); 101 DataSetInit(); 102} 103 104void Report::EnvInit() 105{ 106 const std::string DEFAULT_DIR = "/data/local/tmp/wukong/report/"; 107 startRunTime_ = WuKongUtil::GetInstance()->GetStartRunTime(); 108 // Get a screenshot within the previous timestamp of the current timestamp 109 DIR *dirp = nullptr; 110 dirp = opendir(DEFAULT_DIR.c_str()); 111 std::string maxValue = ""; 112 std::string targetTimeDir; 113 // setting filename 114 currentTestDir_ = WuKongUtil::GetInstance()->GetCurrentTestDir(); 115 INFO_LOG_STR("Report currentTestDir: (%s)", currentTestDir_.c_str()); 116 // setting filename 117 reportCsvFileName_ = currentTestDir_ + "wukong_report.csv"; 118 reportJsonFileName_ = currentTestDir_ + "data.js"; 119 reportFocusInputFileName_ = currentTestDir_ + "focus_report"; 120 121 INFO_LOG_STR("Report CSV: (%s)", reportCsvFileName_.c_str()); 122 INFO_LOG_STR("Report JSON: (%s)", reportJsonFileName_.c_str()); 123 124 reportExceptionDir_ = currentTestDir_ + "exception/"; 125 INFO_LOG_STR("Report exception dir: (%s)", reportExceptionDir_.c_str()); 126 int dirExist = access(reportExceptionDir_.c_str(), F_OK); 127 if (dirExist != 0) { 128 int dirStatus = mkdir((reportExceptionDir_).c_str(), 0777); 129 if (dirStatus == -1) { 130 ERROR_LOG("exception dir create fail"); 131 } 132 } 133 StartCrashDirListen(); 134 // register crash catcher 135 ExceptionManager::GetInstance()->StartCatching(); 136 if (dirp == nullptr) { 137 ERROR_LOG_STR("dir{%s} opendir error", DEFAULT_DIR.c_str()); 138 return; 139 } 140 while (dirp != nullptr) { 141 struct dirent *dp; 142 if ((dp = readdir(dirp)) == NULL) { 143 break; 144 } 145 std::string currentStringName(dp->d_name); 146 if (currentStringName != startRunTime_) { 147 if (currentStringName > maxValue) { 148 maxValue = currentStringName; 149 targetTimeDir = currentStringName; 150 } 151 } 152 } 153 (void)closedir(dirp); 154 // Delete the screenshot under the timestamp 155 std::string targetDir_ = DEFAULT_DIR + targetTimeDir +"/screenshot/"; 156 WuKongUtil::GetInstance()->DeleteFile(targetDir_); 157} 158 159void Report::DataSetInit() 160{ 161 std::shared_ptr<Filter> categoryFilter = std::make_shared<FilterCategory>(); 162 eventDataSet_->SetFilterStragety(categoryFilter); 163 eventDataSet_->SetFilterType("event"); 164 std::shared_ptr<Statistics> eventSatistics = std::make_shared<StatisticsEvent>(); 165 eventDataSet_->SetStatisticsStragety(eventSatistics); 166 167 // set componment filter,statistics,format 168 componmentDataSet_->SetFilterStragety(categoryFilter); 169 componmentDataSet_->SetFilterType("componment"); 170 std::shared_ptr<Statistics> componmentSatistics = std::make_shared<StatisticsComponment>(); 171 componmentDataSet_->SetStatisticsStragety(componmentSatistics); 172 173 // set ability filter,statistics,format 174 abilityDataSet_->SetFilterStragety(categoryFilter); 175 abilityDataSet_->SetFilterType("abilityName"); 176 std::shared_ptr<Statistics> abilitySatistics = std::make_shared<StatisticsAbility>(); 177 abilityDataSet_->SetStatisticsStragety(abilitySatistics); 178 179 // set exception filter,statistics,format 180 exceptionDataSet_->SetFilterStragety(categoryFilter); 181 exceptionDataSet_->SetFilterType("exception"); 182 std::shared_ptr<Statistics> exceptionSatistics = std::make_shared<StatisticsException>(); 183 exceptionDataSet_->SetStatisticsStragety(exceptionSatistics); 184} 185 186void Report::SyncInputInfo(std::shared_ptr<InputedMsgObject> inputedMsgObject) 187{ 188 TRACK_LOG_STD(); 189 std::shared_ptr<AbilityManagerClient> abilityManagerClient = AbilityManagerClient::GetInstance(); 190 OHOS::AppExecFwk::ElementName elementName = abilityManagerClient->GetTopAbility(); 191 std::map<std::string, std::string> data; 192 data["bundleName"] = elementName.GetBundleName(); 193 data["abilityName"] = elementName.GetAbilityName(); 194 DEBUG_LOG_STR("bundleName{%s} abilityName{%s} ", data["bundleName"].c_str(), data["abilityName"].c_str()); 195 SplitInputMode(inputedMsgObject, data); 196 197 // first appswitch abandon 198 std::map<std::string, std::string>::iterator it = data.find("event"); 199 if (it != data.end() && (data["event"] == "appswitch") && (isFirstAppSwitch_ == false)) { 200 DEBUG_LOG("first appswitch abandon"); 201 isFirstAppSwitch_ = true; 202 return; 203 } 204 // record app used to control data display 205 std::vector<std::string>::iterator bundleIter = std::find(bundles_.begin(), bundles_.end(), data["bundleName"]); 206 if (bundleIter == bundles_.end()) { 207 DEBUG_LOG_STR("push apps item{%s}", data["bundleName"].c_str()); 208 bundles_.push_back(data["bundleName"]); 209 } 210 // send `k => v` to filter 211 eventDataSet_->FilterData(data); 212 componmentDataSet_->FilterData(data); 213 abilityDataSet_->FilterData(data); 214 taskCount_++; 215 DEBUG_LOG_STR("taskCount{%d}", taskCount_); 216 if (is_focus_) { 217 GroupFocusDataAndRecord(inputedMsgObject, data); 218 } 219 // statistics and storage every 10 data 220 if ((taskCount_ % SEGMENT_STATISTICS_LENGTH) == 0) { 221 HilogFileRecord(); 222 SegmentedWriteCSV(); 223 SegmentedWriteJson(); 224 if (is_focus_) { 225 SegmentedWriteForFocusInput(); 226 } 227 } 228 TRACK_LOG_END(); 229} 230 231void Report::SplitInputMode(std::shared_ptr<InputedMsgObject> &inputedMsgObject, 232 std::map<std::string, std::string> &data) 233{ 234 inputedMode inputMode = inputedMsgObject->GetInputedMode(); 235 switch (inputMode) { 236 case multimodeInput: { 237 auto inputMutlMsgPtr = std::static_pointer_cast<MultimodeInputMsg>(inputedMsgObject); 238 data["event"] = inputMutlMsgPtr->GetInputType(); 239 DEBUG_LOG_STR("eventType{%s}", data["event"].c_str()); 240 break; 241 } 242 243 case componmentInput: { 244 auto inputCompMsgPtr = std::static_pointer_cast<ComponmentInputMsg>(inputedMsgObject); 245 ComponmentInfoArrange(data["bundleName"], inputCompMsgPtr, data); 246 DEBUG_LOG("componmentType map"); 247 break; 248 } 249 default: 250 break; 251 } 252} 253 254void Report::GroupFocusDataAndRecord(std::shared_ptr<InputedMsgObject> &inputedMsgObject, 255 std::map<std::string, std::string> &data) 256{ 257 TRACK_LOG_STD(); 258 inputedMode inputMode = inputedMsgObject->GetInputedMode(); 259 if (inputMode != componmentInput) { 260 return; 261 } 262 auto inputCompMsgPtr = std::static_pointer_cast<ComponmentInputMsg>(inputedMsgObject); 263 std::string item = ""; 264 time_t currentTime = time(0); 265 std::string timeStr = ""; 266 if (currentTime > 0) { 267 timeStr = std::to_string(currentTime); 268 } 269 item += std::to_string(taskCount_) + ","; 270 item += timeStr + ","; 271 item += data["abilityName"] + ","; 272 item += inputCompMsgPtr->pagePath_ + ","; 273 item += inputCompMsgPtr->componmentType_ + ","; 274 item += std::to_string(inputCompMsgPtr->startX_) + ","; 275 item += std::to_string(inputCompMsgPtr->startY_) + ","; 276 item += std::to_string(inputCompMsgPtr->endX_) + ","; 277 item += std::to_string(inputCompMsgPtr->endY_) + ","; 278 item += inputCompMsgPtr->content_ + ","; 279 item += std::to_string(inputCompMsgPtr->pssTotal_); 280 focus_input_vec_.push_back(item); 281 TRACK_LOG_END(); 282} 283 284Report::~Report() 285{ 286} 287 288void Report::SegmentedWriteCSV() 289{ 290 TRACK_LOG_STD(); 291 // csv report format 292 if (reportCsvFileName_.empty()) { 293 return; 294 } 295 std::shared_ptr<FormatCSV> formatCSV = std::make_shared<FormatCSV>(); 296 eventDataSet_->SetFormatStragety(formatCSV); 297 componmentDataSet_->SetFormatStragety(formatCSV); 298 abilityDataSet_->SetFormatStragety(formatCSV); 299 exceptionDataSet_->SetFormatStragety(formatCSV); 300 std::stringstream modules; 301 modules << "module, Base Info" << std::endl; 302 modules << "name, base" << std::endl; 303 modules << "detail, info" << std::endl; 304 modules << "name, base, detail, info" << std::endl; 305 modules << "task status, success" << std::endl; 306 modules << "task time , " << time(0) - startTime_ << std::endl; 307 if (!seed_.empty()) { 308 modules << "seed , " << seed_ << std::endl; 309 } 310 modules << "task count , " << taskCount_ << std::endl; 311 DEBUG_LOG("start event statistics"); 312 eventDataSet_->StatisticsData(); 313 DEBUG_LOG("end event statistics"); 314 DEBUG_LOG("start componment statistics"); 315 componmentDataSet_->StatisticsData(); 316 DEBUG_LOG("end componment statistics"); 317 std::string moduleInput; 318 modules << "module, Input Message Statistics" << std::endl; 319 modules << "name, all"; 320 // show all app and detail 321 for (auto bundleIter : bundles_) { 322 modules << ", " << bundleIter; 323 } 324 modules << std::endl; 325 modules << "detail, event, componment" << std::endl; 326 eventDataSet_->FormatData("all", moduleInput); 327 componmentDataSet_->FormatData("all", moduleInput); 328 // loop app show name-type statistics content 329 for (auto bundleIter : bundles_) { 330 eventDataSet_->FormatData(bundleIter, moduleInput); 331 componmentDataSet_->FormatData(bundleIter, moduleInput); 332 } 333 modules << moduleInput; 334 modules << "module, ability Statistics" << std::endl; 335 modules << "name, all" << std::endl; 336 modules << "detail, ability" << std::endl; 337 moduleInput = ""; 338 abilityDataSet_->StatisticsData(); 339 abilityDataSet_->FormatData("all", moduleInput); 340 modules << moduleInput; 341 342 std::unique_lock<std::mutex> locker(crashMtx_); 343 modules << "module, Exception Message Statistics" << std::endl; 344 modules << "name, exception" << std::endl; 345 modules << "detail, statistics" << std::endl; 346 moduleInput = ""; 347 exceptionDataSet_->StatisticsData(); 348 exceptionDataSet_->FormatData("exception", moduleInput); 349 modules << moduleInput; 350 locker.unlock(); 351 std::string csvContent = modules.str(); 352 std::fstream csvFileStream(reportCsvFileName_, std::ios::out | std::ios::trunc); 353 csvFileStream << csvContent << std::endl; 354 csvFileStream.close(); 355 TRACK_LOG_END(); 356} 357 358void Report::SegmentedWriteJson() 359{ 360 TRACK_LOG_STD(); 361 DEBUG_LOG("SegmentedWriteJson start"); 362 // csv report format 363 if (reportCsvFileName_.empty()) { 364 return; 365 } 366 std::shared_ptr<FormatJSON> formatJSON = std::make_shared<FormatJSON>(); 367 eventDataSet_->SetFormatStragety(formatJSON); 368 componmentDataSet_->SetFormatStragety(formatJSON); 369 abilityDataSet_->SetFormatStragety(formatJSON); 370 exceptionDataSet_->SetFormatStragety(formatJSON); 371 std::stringstream modules; 372 std::string moduleInput; 373 modules << "var reportJson = {" << std::endl; 374 modules << "base: [" << std::endl; 375 modules << "{ item: \"task status\", detail: \" success \"}," << std::endl; 376 modules << "{ item: \"task time\", detail: \" " << time(0) - startTime_ << "s\"}," << std::endl; 377 modules << "{ item: \"task count\", detail: \" " << taskCount_ << "\"}," << std::endl; 378 if (!seed_.empty()) { 379 modules << "{ item: \"seed\", detail: \" " << seed_ << "\"}," << std::endl; 380 } 381 modules << "]," << std::endl; 382 modules << "detailApps:{" << std::endl; 383 modules << "names:[ \"all\""; 384 // show all app and detail 385 for (auto bundleIter : bundles_) { 386 modules << ", \"" << bundleIter << " \""; 387 } 388 modules << "]," << std::endl; 389 modules << "details: [" << std::endl; 390 modules << "{" << std::endl; 391 modules << "eventStatistics:" << std::endl; 392 eventDataSet_->FormatData("all", moduleInput); 393 modules << moduleInput; 394 modules << "controlStatistics:"; 395 componmentDataSet_->FormatData("all", moduleInput); 396 modules << moduleInput; 397 modules << "},"; 398 // loop app show name-type statistics content 399 for (auto bundleIter : bundles_) { 400 modules << "{" << std::endl; 401 modules << "eventStatistics:"; 402 eventDataSet_->FormatData(bundleIter, moduleInput); 403 modules << moduleInput; 404 modules << "controlStatistics:"; 405 componmentDataSet_->FormatData(bundleIter, moduleInput); 406 modules << moduleInput; 407 modules << "},"; 408 } 409 modules << "]" << std::endl; 410 modules << "}," << std::endl; 411 modules << "abilityStatistics:"; 412 abilityDataSet_->FormatData("all", moduleInput); 413 modules << moduleInput; 414 modules << "detailException: {" << std::endl; 415 modules << "names: [\"exception statistics\", \"cpp crash statistics\", \"js crash statistics\"]," << std::endl; 416 modules << "details: [" << std::endl; 417 modules << "{" << std::endl; 418 modules << "exception_statistics: {" << std::endl; 419 modules << "header: [\"Type\", \"Times\", \"Proportion\"]," << std::endl; 420 modules << "content: " << std::endl; 421 exceptionDataSet_->FormatData("exception", moduleInput); 422 modules << moduleInput; 423 modules << "}," << std::endl; 424 modules << "}," << std::endl; 425 modules << "]" << std::endl; 426 modules << "}," << std::endl; 427 unsigned int index = 0; 428 modules << "screens:[" << std::endl; 429 for (auto srceen : screenPaths_) { 430 modules << "{index:\"" << index << "\"," 431 << "path:\"" << srceen << "\"}," << std::endl; 432 index++; 433 } 434 modules << "]," << std::endl; 435 modules << "};" << std::endl; 436 std::string jsonContent = modules.str(); 437 std::fstream jsonFileStream(reportJsonFileName_, std::ios::out | std::ios::trunc); 438 jsonFileStream << jsonContent << std::endl; 439 jsonFileStream.close(); 440 DEBUG_LOG("SegmentedWriteJson end"); 441 TRACK_LOG_END(); 442} 443 444void Report::SegmentedWriteForFocusInput() 445{ 446 TRACK_LOG_STD(); 447 DEBUG_LOG("SegmentedWriteForFocusInput start"); 448 // csv report format 449 if (reportFocusInputFileName_.empty()) { 450 return; 451 } 452 453 std::stringstream modules; 454 for (size_t i = 0; i < focus_input_vec_.size(); ++i) { 455 modules << focus_input_vec_[i]; 456 if (i < focus_input_vec_.size() - 1) { 457 modules << std::endl; 458 } 459 } 460 focus_input_vec_.clear(); 461 std::string jsonContent = modules.str(); 462 std::fstream jsonFileStream(reportFocusInputFileName_, std::ios::app); 463 jsonFileStream << jsonContent << std::endl; 464 jsonFileStream.close(); 465 DEBUG_LOG("SegmentedWriteForFocusInput end"); 466 TRACK_LOG_END(); 467} 468 469void Report::HilogFileRecord() 470{ 471 struct dirent *dp; 472 DIR *dirpHilog = nullptr; 473 std::shared_ptr<WuKongUtil> utilPtr = WuKongUtil::GetInstance(); 474 dirpHilog = opendir(hilogDirs_.c_str()); 475 if (dirpHilog == nullptr) { 476 ERROR_LOG_STR("dir{%s} opendir error", hilogDirs_.c_str()); 477 return; 478 } 479 while ((dp = readdir(dirpHilog)) != NULL) { 480 std::string targetFile(dp->d_name); 481 if ((strcmp(dp->d_name, ".") != 0) && (strcmp(dp->d_name, "..") != 0)) { 482 std::vector<std::string>::iterator iterDir = find(hilogFiles_.begin(), hilogFiles_.end(), targetFile); 483 if (iterDir == hilogFiles_.end()) { 484 DEBUG_LOG("hilog copy action"); 485 utilPtr->CopyFile(targetFile, hilogDirs_, reportExceptionDir_); 486 hilogFiles_.push_back(targetFile); 487 } 488 } 489 } 490 if (dirpHilog != nullptr) { 491 (void)closedir(dirpHilog); 492 } 493} 494 495void Report::ExceptionRecord(const std::string &exceptionFilename) 496{ 497 std::unique_lock<std::mutex> locker(crashMtx_); 498 std::map<std::string, std::string> data; 499 std::string exceptionType; 500 if (exceptionFilename.find("cppcrash") != std::string::npos) { 501 exceptionType = "cppcrash"; 502 } 503 504 if (exceptionFilename.find("appfreeze") != std::string::npos) { 505 exceptionType = "appfreeze"; 506 } 507 508 if (exceptionFilename.find("jscrash") != std::string::npos) { 509 exceptionType = "jscrash"; 510 } 511 512 if (exceptionFilename.find("serviceblock") != std::string::npos) { 513 exceptionType = "serviceblock"; 514 } 515 516 data["exception"] = exceptionType; 517 exceptionDataSet_->FilterData(data); 518} 519 520void Report::Finish() 521{ 522 SegmentedWriteCSV(); 523 SegmentedWriteJson(); 524 if (is_focus_) { 525 SegmentedWriteForFocusInput(); 526 } 527 ExceptionManager::GetInstance()->StopCatching(); 528} 529 530void Report::SetSeed(std::string seed) 531{ 532 seed_ = seed; 533} 534 535void Report::ComponmentInfoArrange(const std::string &bundle, std::shared_ptr<ComponmentInputMsg> inputCompMsgPtr, 536 std::map<std::string, std::string> &data) 537{ 538 std::map<std::string, componmentRecord>::iterator bundleComponmentRecordIter; 539 componmentRecord componmentRecord; 540 bundleComponmentRecordIter = bundleComponmentRecord_.find(bundle); 541 if (bundleComponmentRecordIter != bundleComponmentRecord_.end()) { 542 componmentRecord = bundleComponmentRecordIter->second; 543 } 544 componmentRecord.pageIdComponments[inputCompMsgPtr->pageId_] = inputCompMsgPtr->pageComponments; 545 std::map<std::string, uint32_t>::iterator componmentTypeCountIter; 546 uint32_t componmentTypeInputedCount = 0; 547 uint32_t componmentTypeTotal = 0; 548 componmentTypeCountIter = componmentRecord.componmentTypeCount.find(inputCompMsgPtr->componmentType_); 549 if (componmentTypeCountIter != componmentRecord.componmentTypeCount.end()) { 550 componmentTypeInputedCount = componmentTypeCountIter->second; 551 } 552 componmentTypeInputedCount++; 553 554 for (auto pageIdComponmentsIter : componmentRecord.pageIdComponments) { 555 for (auto componmentVectorIter : pageIdComponmentsIter.second) { 556 if (componmentVectorIter.compare(inputCompMsgPtr->componmentType_) == 0) { 557 componmentTypeTotal++; 558 } 559 } 560 } 561 if (componmentTypeInputedCount > componmentTypeTotal) { 562 componmentTypeInputedCount = componmentTypeTotal; 563 } 564 565 componmentRecord.componmentTypeCount[inputCompMsgPtr->componmentType_] = componmentTypeInputedCount; 566 data["componment"] = inputCompMsgPtr->componmentType_; 567 data["inputedTimes"] = std::to_string(componmentTypeInputedCount); 568 data["componmentTotals"] = std::to_string(componmentTypeTotal); 569 DEBUG_LOG_STR("componmentType{%s} inputedTimes{%s} componmentTotals{%s}", data["componment"].c_str(), 570 data["inputedTimes"].c_str(), data["componmentTotals"].c_str()); 571 bundleComponmentRecord_[bundle] = componmentRecord; 572} 573 574void Report::RecordScreenPath(const std::string &screenPath) 575{ 576 TRACK_LOG_STD(); 577 screenPaths_.push_back(screenPath); 578 TRACK_LOG_END(); 579} 580 581std::string Report::GetReportExceptionDir() 582{ 583 return reportExceptionDir_; 584} 585} // namespace WuKong 586} // namespace OHOS