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 "avcodec_log_dump.h"
17 #include <fstream>
18 #include <unistd.h>
19 #include <malloc.h>
20 #include <sys/time.h>
21 #include "securec.h"
22 #include "avcodec_log.h"
23
24 namespace {
25 constexpr int32_t FILE_MAX = 100;
26 constexpr int32_t FILE_LINE_MAX = 50000;
27 constexpr ::OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "AVCodecLogDump"};
28 }
29
30 namespace OHOS {
31 namespace MediaAVCodec {
GetInstance()32 AVCodecLogDump &AVCodecLogDump::GetInstance()
33 {
34 static AVCodecLogDump avcodecLogDump;
35 return avcodecLogDump;
36 }
37
AVCodecLogDump()38 AVCodecLogDump::AVCodecLogDump()
39 {
40 CHECK_AND_RETURN_LOG(thread_ == nullptr, "TaskProcessor is existed");
41 thread_ = std::make_unique<std::thread>(&AVCodecLogDump::TaskProcessor, this);
42 }
43
~AVCodecLogDump()44 AVCodecLogDump::~AVCodecLogDump()
45 {
46 {
47 std::unique_lock<std::mutex> lock(mutex_);
48 isExit_ = true;
49 cond_.notify_all();
50 }
51 if (thread_ != nullptr && thread_->joinable()) {
52 thread_->join();
53 }
54 }
55
AddNewLog(std::string & logStr)56 static void AddNewLog(std::string &logStr)
57 {
58 struct timeval time = {};
59 (void)gettimeofday(&time, nullptr);
60 int64_t second = time.tv_sec % 60;
61 int64_t allMinute = time.tv_sec / 60;
62 int64_t minute = allMinute % 60;
63 int64_t hour = allMinute / 60 % 24;
64 int64_t mSecond = time.tv_usec / 1000;
65
66 logStr += std::to_string(hour);
67 logStr += ":";
68 logStr += std::to_string(minute);
69 logStr += ":";
70 logStr += std::to_string(second);
71 logStr += ":";
72 logStr += std::to_string(mSecond);
73 logStr += " ";
74 logStr += " pid:";
75 logStr += std::to_string(getpid());
76 logStr += " tid:";
77 logStr += std::to_string(gettid());
78 logStr += " ";
79 }
80
SaveLog(const char * fmt,...)81 void AVCodecLogDump::SaveLog(const char *fmt, ...)
82 {
83 std::unique_lock<std::mutex> lock(mutex_);
84 if (!isEnable_) {
85 return;
86 }
87 std::string temp = "";
88 std::string fmtStr = fmt;
89 int32_t srcPos = 0;
90 auto dtsPos = fmtStr.find("{public}", srcPos);
91 const int32_t pubLen = 8;
92 while (dtsPos != std::string::npos) {
93 temp += fmtStr.substr(srcPos, dtsPos - srcPos);
94 srcPos = static_cast<int32_t>(dtsPos) + pubLen;
95 dtsPos = fmtStr.find("{public}", srcPos);
96 }
97 temp += fmtStr.substr(srcPos);
98
99 va_list ap;
100 va_start(ap, fmt);
101 constexpr uint8_t maxLogLen = 255;
102 char logBuf[maxLogLen];
103 auto ret = vsnprintf_s(logBuf, maxLogLen, maxLogLen - 1, temp.c_str(), ap);
104 va_end(ap);
105
106 AddNewLog(logString_);
107 if (ret < 0) {
108 logString_ += "dump log error";
109 } else {
110 logString_ += logBuf;
111 }
112 logString_ += "\n";
113 lineCount_++;
114 if (lineCount_ >= FILE_LINE_MAX) {
115 cond_.notify_all();
116 }
117 }
118
UpdateCheckEnable()119 void AVCodecLogDump::UpdateCheckEnable()
120 {
121 std::string file = "/data/media/log/check.config";
122 std::ofstream ofStream(file);
123 if (!ofStream.is_open()) {
124 isEnable_ = false;
125 return;
126 }
127 ofStream.close();
128 isEnable_ = true;
129 }
130
TaskProcessor()131 void AVCodecLogDump::TaskProcessor()
132 {
133 pthread_setname_np(pthread_self(), "AVCodecLogDumpTask");
134 (void)mallopt(M_SET_THREAD_CACHE, M_THREAD_CACHE_DISABLE);
135 (void)mallopt(M_DELAYED_FREE, M_DELAYED_FREE_DISABLE);
136 while (true) {
137 std::string temp;
138 int32_t lineCount = 0;
139 {
140 std::unique_lock<std::mutex> lock(mutex_);
141 if (isExit_) {
142 return;
143 }
144 static constexpr int32_t timeout = 60; // every 1 minute have a log
145 cond_.wait_for(lock, std::chrono::seconds(timeout),
146 [this] {
147 UpdateCheckEnable();
148 return isExit_ || isDump_ || lineCount_ >= FILE_LINE_MAX || !logString_.empty();
149 });
150 isDump_ = false;
151 lineCount = lineCount_;
152 lineCount_ = lineCount_ >= FILE_LINE_MAX ? 0 : lineCount_;
153 swap(logString_, temp);
154 }
155
156 std::string file = "/data/media/avcodec/log/";
157 file += std::to_string(getpid());
158 file += "dump_log_avcodec.log";
159 file += std::to_string(fileCount_);
160 std::ofstream ofStream;
161 if (isNewFile_) {
162 ofStream.open(file, std::ios::out | std::ios::trunc);
163 } else {
164 ofStream.open(file, std::ios::out | std::ios::app);
165 }
166 if (!ofStream.is_open()) {
167 continue;
168 }
169 isNewFile_ = false;
170 if (lineCount >= FILE_LINE_MAX) {
171 isNewFile_ = true;
172 fileCount_++;
173 fileCount_ = fileCount_ > FILE_MAX ? 0 : fileCount_;
174 }
175 ofStream.write(temp.c_str(), temp.size());
176 ofStream.close();
177 }
178 }
179 } // namespace MediaAVCodec
180 } // namespace OHOS