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 <sys/time.h>
17 #include <fstream>
18 #include <sstream>
19 #include <cstdio>
20 #include "camera_dump.h"
21 #include "v1_0/vdi_types.h"
22 #include "camera.h"
23
24 using namespace std;
25
26 namespace OHOS::Camera {
27 const std::string DUMP_PATH = "/data/local/tmp/";
28 constexpr uint32_t ARGS_MAX_NUM = 5;
29 constexpr uint32_t PATH_MAX_LEN = 200;
30 constexpr int32_t READ_DISKINFO_NUM = 6;
31 constexpr uint32_t MAX_USAGE_RATE = 70;
32 constexpr int32_t CHECK_DISKINFO_TIME_MS = 10000;
33 #define TITLEINFO_ARRAY_SIZE 200
34
35 const char *g_cameraDumpHelp =
36 " Camera manager dump options:\n"
37 " -h: camera dump help\n"
38 " -m: start dump metadata\n"
39 " -b: start dump buffer\n"
40 " -e: exit all dump\n";
41
42 std::map<DumpType, bool> g_dumpInfoMap = {
43 {MedataType, false},
44 {BufferType, false}
45 };
46
47 struct DiskInfo {
48 char diskName[100];
49 uint32_t diskTotal;
50 uint32_t diskUse;
51 uint32_t canUse;
52 uint32_t diskUsePer;
53 char diskMountInfo[200];
54 };
55
~CameraDumper()56 CameraDumper::~CameraDumper()
57 {
58 StopCheckDiskInfo();
59 }
60
DumpBuffer(const std::shared_ptr<IBuffer> & buffer)61 bool CameraDumper::DumpBuffer(const std::shared_ptr<IBuffer>& buffer)
62 {
63 if (buffer == nullptr) {
64 CAMERA_LOGE("buffer is nullptr");
65 return false;
66 }
67
68 if (!IsDumpOpened(BufferType)) {
69 return false;
70 }
71
72 uint32_t size = buffer->GetSize();
73 uint32_t width = buffer->GetWidth();
74 void* addr = buffer->GetVirAddress();
75 uint32_t height = buffer->GetHeight();
76 int32_t streamId = buffer->GetStreamId();
77 int32_t captureId = buffer->GetCaptureId();
78 int32_t encodeType = buffer->GetEncodeType();
79 EsFrameInfo esInfo = buffer->GetEsFrameInfo();
80 size = esInfo.size > 0 ? esInfo.size : size;
81
82 std::stringstream ss;
83 std::string fileName;
84 ss << "captureId[" << captureId << "]_streamId[" << streamId <<
85 "]_width[" << width << "]_height[" << height;
86
87 if (encodeType == VDI::Camera::V1_0::ENCODE_TYPE_JPEG) {
88 ss << "]_" << GetCurrentLocalTimeStamp();
89 ss >> fileName;
90 fileName += ".jpeg";
91 } else if (encodeType == VDI::Camera::V1_0::ENCODE_TYPE_H264) {
92 ss << "]_" << GetCurrentLocalTimeStamp();
93 ss >> fileName;
94 fileName += "video.yuv";
95 } else {
96 ss << "]_" << GetCurrentLocalTimeStamp();
97 ss >> fileName;
98 fileName += ".yuv";
99 }
100
101 return SaveDataToFile(fileName.c_str(), addr, size);
102 }
103
DumpMetadata(const std::shared_ptr<CameraMetadata> & metadata,std::string tag)104 bool CameraDumper::DumpMetadata(const std::shared_ptr<CameraMetadata>& metadata, std::string tag)
105 {
106 if (metadata == nullptr) {
107 CAMERA_LOGE("metadata is nullptr");
108 return false;
109 }
110
111 if (!IsDumpOpened(MedataType)) {
112 return false;
113 }
114
115 common_metadata_header_t *data = metadata->get();
116 if (data == nullptr) {
117 CAMERA_LOGE("data is nullptr");
118 return false;
119 }
120 std::string metaStr = FormatCameraMetadataToString(data);
121 if (metaStr.size() == 0) {
122 CAMERA_LOGE("metaStr.size is 0");
123 return true;
124 }
125 std::stringstream ss;
126 ss << GetCurrentLocalTimeStamp() << "_" << tag << ".meta";
127
128 return SaveDataToFile(ss.str().c_str(), metaStr.c_str(), metaStr.size());
129 }
130
UpdateDumpMode(DumpType type,bool isDump,HdfSBuf * reply)131 void CameraDumper::UpdateDumpMode(DumpType type, bool isDump, HdfSBuf *reply)
132 {
133 std::string upRetStr;
134 {
135 std::lock_guard<std::mutex> l(dumpStateLock_);
136 auto it = g_dumpInfoMap.find(type);
137 if (it != g_dumpInfoMap.end()) {
138 g_dumpInfoMap[type] = isDump;
139 upRetStr += " set dump mode success!\n";
140 }
141 }
142
143 if (reply != nullptr) {
144 (void)HdfSbufWriteString(reply, upRetStr.c_str());
145 }
146
147 if (isDump) {
148 StartCheckDiskInfo();
149 } else {
150 StopCheckDiskInfo();
151 }
152 }
153
IsDumpOpened(DumpType type)154 bool CameraDumper::IsDumpOpened(DumpType type)
155 {
156 std::lock_guard<std::mutex> l(dumpStateLock_);
157 return g_dumpInfoMap.find(type) != g_dumpInfoMap.end() && g_dumpInfoMap[type];
158 }
159
SaveDataToFile(const char * fileName,const void * data,uint32_t size)160 bool CameraDumper::SaveDataToFile(const char *fileName, const void *data, uint32_t size)
161 {
162 std::stringstream mkdirCmd;
163 mkdirCmd << "mkdir -p " << DUMP_PATH;
164 system(mkdirCmd.str().c_str());
165
166 std::stringstream ss;
167 ss << DUMP_PATH << fileName;
168 std::ofstream ofs(ss.str(), std::ios::app);
169
170 if (!ofs.good()) {
171 CAMERA_LOGE("open dump file <%{public}s> failed, error: %{public}s", ss.str().c_str(), std::strerror(errno));
172 return false;
173 }
174
175 ofs.write(static_cast<const char *>(data), size);
176 ofs.close();
177
178 return true;
179 }
180
GetCurrentLocalTimeStamp()181 uint64_t CameraDumper::GetCurrentLocalTimeStamp()
182 {
183 std::chrono::time_point<std::chrono::system_clock, std::chrono::milliseconds> tp =
184 std::chrono::time_point_cast<std::chrono::milliseconds>(std::chrono::system_clock::now());
185 auto tmp = std::chrono::duration_cast<std::chrono::milliseconds>(tp.time_since_epoch());
186 return static_cast<uint64_t>(tmp.count());
187 }
188
ShowDumpMenu(HdfSBuf * reply)189 void CameraDumper::ShowDumpMenu(HdfSBuf *reply)
190 {
191 if (reply != nullptr) {
192 (void)HdfSbufWriteString(reply, g_cameraDumpHelp);
193 }
194 }
195
CameraHostDumpProcess(HdfSBuf * data,HdfSBuf * reply)196 void CameraDumper::CameraHostDumpProcess(HdfSBuf *data, HdfSBuf *reply)
197 {
198 if (data == nullptr || reply == nullptr) {
199 CAMERA_LOGE("%{public}s is nullptr", (data == nullptr) ? "data" : "reply");
200 return;
201 }
202
203 uint32_t argsNum;
204 if (!HdfSbufReadUint32(data, &argsNum)) {
205 CAMERA_LOGE("read argsNum failed!");
206 return;
207 }
208
209 if (argsNum <= 0 || argsNum > ARGS_MAX_NUM) {
210 (void)HdfSbufWriteString(reply, g_cameraDumpHelp);
211 return;
212 }
213
214 for (uint32_t i = 0; i < argsNum; i++) {
215 const char *value = HdfSbufReadString(data);
216 if (value == NULL) {
217 CAMERA_LOGE("arg is invalid i: %{public}u", i);
218 return;
219 }
220 if (strcmp(value, "-m") == 0) {
221 UpdateDumpMode(MedataType, true, reply);
222 } else if (strcmp(value, "-b") == 0) {
223 UpdateDumpMode(BufferType, true, reply);
224 } else if (strcmp(value, "-e") == 0) {
225 UpdateDumpMode(BufferType, false, reply);
226 UpdateDumpMode(MedataType, false, reply);
227 } else {
228 ShowDumpMenu(reply);
229 }
230 }
231 }
232
CameraDumpEvent(HdfSBuf * data,HdfSBuf * reply)233 int32_t CameraDumpEvent(HdfSBuf *data, HdfSBuf *reply)
234 {
235 CameraDumper& dumper = CameraDumper::GetInstance();
236 dumper.CameraHostDumpProcess(data, reply);
237 return HDF_SUCCESS;
238 }
239
CheckDiskInfo()240 void CameraDumper::CheckDiskInfo()
241 {
242 DiskInfo diskInfo;
243 auto ret = memset_s(&diskInfo, sizeof(DiskInfo), 0, sizeof(DiskInfo));
244 if (ret != EOK) {
245 CAMERA_LOGE("diskInfo memset failed!");
246 return;
247 }
248 stringstream ss;
249 ss << "df " << DUMP_PATH;
250
251 FILE *fp = popen(ss.str().c_str(), "r");
252 if (fp == NULL) {
253 CAMERA_LOGE("popen failed, cmd : %{public}s", ss.str().c_str());
254 return;
255 }
256
257 char titleInfo[TITLEINFO_ARRAY_SIZE] = {0};
258 fgets(titleInfo, sizeof(titleInfo) / sizeof(titleInfo[0]) - 1, fp);
259 int readNum = fscanf_s(fp, "%s %u %u %u %u%% %s\n", diskInfo.diskName, sizeof(diskInfo.diskName) - 1,
260 &diskInfo.diskTotal, &diskInfo.diskUse, &diskInfo.canUse, &diskInfo.diskUsePer, diskInfo.diskMountInfo,
261 sizeof(diskInfo.diskMountInfo) - 1);
262 pclose(fp);
263
264 if (readNum != READ_DISKINFO_NUM) {
265 CAMERA_LOGW("readNum != READ_DISKINFO_NUM readNum: %{public}d", readNum);
266 return;
267 }
268
269 if (diskInfo.diskUsePer >= MAX_USAGE_RATE) {
270 std::lock_guard<std::mutex> l(dumpStateLock_);
271 for (auto it = g_dumpInfoMap.begin(); it != g_dumpInfoMap.end(); it++) {
272 it->second = false;
273 }
274 CAMERA_LOGD("readNum: %{public}d, diskName: %{public}s, diskUsePer: %{public}u%% diskMountInfo: %{public}s",
275 readNum, diskInfo.diskName, diskInfo.diskUsePer, diskInfo.diskMountInfo);
276 }
277 }
278
ThreadWorkFun()279 void CameraDumper::ThreadWorkFun()
280 {
281 while (true) {
282 CheckDiskInfo();
283
284 std::unique_lock<std::mutex> l(terminateLock_);
285 cv_.wait_for(l, std::chrono::milliseconds(CHECK_DISKINFO_TIME_MS),
286 [this]() {
287 return terminate_;
288 }
289 );
290
291 if (terminate_) {
292 break;
293 }
294 }
295 }
296
StartCheckDiskInfo()297 void CameraDumper::StartCheckDiskInfo()
298 {
299 {
300 std::unique_lock<std::mutex> l(terminateLock_);
301 if (terminate_ == false) {
302 CAMERA_LOGD("thread is already start");
303 return;
304 }
305 terminate_ = false;
306 }
307
308 handleThread_ = std::make_unique<std::thread>(&CameraDumper::ThreadWorkFun, this);
309 }
310
StopCheckDiskInfo()311 void CameraDumper::StopCheckDiskInfo()
312 {
313 {
314 std::unique_lock<std::mutex> l(terminateLock_);
315 if (terminate_ == true) {
316 CAMERA_LOGW("thread is already stop");
317 return;
318 }
319 terminate_ = true;
320 cv_.notify_one();
321 }
322 if (handleThread_ != nullptr && handleThread_->joinable()) {
323 handleThread_->join();
324 handleThread_ = nullptr;
325 }
326 }
327 } // namespace OHOS::Camera
328