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 fileName = "cameraDumpVideo.h264";
93 } else {
94 ss << "]_" << GetCurrentLocalTimeStamp();
95 ss >> fileName;
96 fileName += ".yuv";
97 }
98
99 return SaveDataToFile(fileName.c_str(), addr, size);
100 }
101
DumpMetadata(const std::shared_ptr<CameraMetadata> & metadata,std::string tag)102 bool CameraDumper::DumpMetadata(const std::shared_ptr<CameraMetadata>& metadata, std::string tag)
103 {
104 if (metadata == nullptr) {
105 CAMERA_LOGE("metadata is nullptr");
106 return false;
107 }
108
109 if (!IsDumpOpened(MedataType)) {
110 return false;
111 }
112
113 common_metadata_header_t *data = metadata->get();
114 if (data == nullptr) {
115 CAMERA_LOGE("data is nullptr");
116 return false;
117 }
118 std::string metaStr = FormatCameraMetadataToString(data);
119 if (metaStr.size() == 0) {
120 CAMERA_LOGE("metaStr.size is 0");
121 return true;
122 }
123 std::stringstream ss;
124 ss << GetCurrentLocalTimeStamp() << "_" << tag << ".meta";
125
126 return SaveDataToFile(ss.str().c_str(), metaStr.c_str(), metaStr.size());
127 }
128
UpdateDumpMode(DumpType type,bool isDump,HdfSBuf * reply)129 void CameraDumper::UpdateDumpMode(DumpType type, bool isDump, HdfSBuf *reply)
130 {
131 std::string upRetStr;
132 {
133 std::lock_guard<std::mutex> l(dumpStateLock_);
134 auto it = g_dumpInfoMap.find(type);
135 if (it != g_dumpInfoMap.end()) {
136 g_dumpInfoMap[type] = isDump;
137 upRetStr += " set dump mode success!\n";
138 }
139 }
140
141 if (reply != nullptr) {
142 (void)HdfSbufWriteString(reply, upRetStr.c_str());
143 }
144
145 if (isDump) {
146 StartCheckDiskInfo();
147 } else {
148 StopCheckDiskInfo();
149 }
150 }
151
IsDumpOpened(DumpType type)152 bool CameraDumper::IsDumpOpened(DumpType type)
153 {
154 std::lock_guard<std::mutex> l(dumpStateLock_);
155 if (g_dumpInfoMap.find(type) != g_dumpInfoMap.end() && g_dumpInfoMap[type]) {
156 return true;
157 }
158 return false;
159 }
160
SaveDataToFile(const char * fileName,const void * data,uint32_t size)161 bool CameraDumper::SaveDataToFile(const char *fileName, const void *data, uint32_t size)
162 {
163 std::stringstream mkdirCmd;
164 mkdirCmd << "mkdir -p " << DUMP_PATH;
165 system(mkdirCmd.str().c_str());
166
167 std::stringstream ss;
168 ss << DUMP_PATH << fileName;
169 std::ofstream ofs(ss.str(), std::ios::app);
170
171 if (!ofs.good()) {
172 CAMERA_LOGE("open dump file <%{public}s> failed, error: %{public}s", ss.str().c_str(), std::strerror(errno));
173 return false;
174 }
175
176 ofs.write(static_cast<const char *>(data), size);
177 ofs.close();
178
179 return true;
180 }
181
GetCurrentLocalTimeStamp()182 uint64_t CameraDumper::GetCurrentLocalTimeStamp()
183 {
184 std::chrono::time_point<std::chrono::system_clock, std::chrono::milliseconds> tp =
185 std::chrono::time_point_cast<std::chrono::milliseconds>(std::chrono::system_clock::now());
186 auto tmp = std::chrono::duration_cast<std::chrono::milliseconds>(tp.time_since_epoch());
187 return static_cast<uint64_t>(tmp.count());
188 }
189
ShowDumpMenu(HdfSBuf * reply)190 void CameraDumper::ShowDumpMenu(HdfSBuf *reply)
191 {
192 if (reply != nullptr) {
193 (void)HdfSbufWriteString(reply, g_cameraDumpHelp);
194 }
195 }
196
CameraHostDumpProcess(HdfSBuf * data,HdfSBuf * reply)197 void CameraDumper::CameraHostDumpProcess(HdfSBuf *data, HdfSBuf *reply)
198 {
199 if (data == nullptr || reply == nullptr) {
200 CAMERA_LOGE("%{public}s is nullptr", (data == nullptr) ? "data" : "reply");
201 return;
202 }
203
204 uint32_t argsNum;
205 if (!HdfSbufReadUint32(data, &argsNum)) {
206 CAMERA_LOGE("read argsNum failed!");
207 return;
208 }
209
210 if (argsNum <= 0 || argsNum > ARGS_MAX_NUM) {
211 (void)HdfSbufWriteString(reply, g_cameraDumpHelp);
212 return;
213 }
214
215 for (uint32_t i = 0; i < argsNum; i++) {
216 const char *value = HdfSbufReadString(data);
217 if (value == NULL) {
218 CAMERA_LOGE("arg is invalid i: %{public}u", i);
219 return;
220 }
221 if (strcmp(value, "-m") == 0) {
222 UpdateDumpMode(MedataType, true, reply);
223 } else if (strcmp(value, "-b") == 0) {
224 UpdateDumpMode(BufferType, true, reply);
225 } else if (strcmp(value, "-e") == 0) {
226 UpdateDumpMode(BufferType, false, reply);
227 UpdateDumpMode(MedataType, false, reply);
228 } else {
229 ShowDumpMenu(reply);
230 }
231 }
232 }
233
CameraDumpEvent(HdfSBuf * data,HdfSBuf * reply)234 int32_t CameraDumpEvent(HdfSBuf *data, HdfSBuf *reply)
235 {
236 CameraDumper& dumper = CameraDumper::GetInstance();
237 dumper.CameraHostDumpProcess(data, reply);
238 return HDF_SUCCESS;
239 }
240
CheckDiskInfo()241 void CameraDumper::CheckDiskInfo()
242 {
243 DiskInfo diskInfo;
244 auto ret = memset_s(&diskInfo, sizeof(DiskInfo), 0, sizeof(DiskInfo));
245 if (ret != EOK) {
246 CAMERA_LOGE("diskInfo memset failed!");
247 return;
248 }
249 stringstream ss;
250 ss << "df " << DUMP_PATH;
251
252 FILE *fp = popen(ss.str().c_str(), "r");
253 if (fp == NULL) {
254 CAMERA_LOGE("popen failed, cmd : %{public}s", ss.str().c_str());
255 return;
256 }
257
258 char titleInfo[TITLEINFO_ARRAY_SIZE] = {0};
259 fgets(titleInfo, sizeof(titleInfo) / sizeof(titleInfo[0]) - 1, fp);
260 int readNum = fscanf_s(fp, "%s %u %u %u %u%% %s\n", diskInfo.diskName, sizeof(diskInfo.diskName) - 1,
261 &diskInfo.diskTotal, &diskInfo.diskUse, &diskInfo.canUse, &diskInfo.diskUsePer, diskInfo.diskMountInfo,
262 sizeof(diskInfo.diskMountInfo) - 1);
263 pclose(fp);
264
265 if (readNum != READ_DISKINFO_NUM) {
266 CAMERA_LOGD("readNum != READ_DISKINFO_NUM readNum: %{public}d", readNum);
267 return;
268 }
269
270 if (diskInfo.diskUsePer >= MAX_USAGE_RATE) {
271 std::lock_guard<std::mutex> l(dumpStateLock_);
272 for (auto it = g_dumpInfoMap.begin(); it != g_dumpInfoMap.end(); it++) {
273 it->second = false;
274 }
275 CAMERA_LOGD("readNum: %{public}d, diskName: %{public}s, diskUsePer: %{public}u%% diskMountInfo: %{public}s",
276 readNum, diskInfo.diskName, diskInfo.diskUsePer, diskInfo.diskMountInfo);
277 }
278 }
279
ThreadWorkFun()280 void CameraDumper::ThreadWorkFun()
281 {
282 while (true) {
283 CheckDiskInfo();
284
285 std::unique_lock<std::mutex> l(terminateLock_);
286 cv_.wait_for(l, std::chrono::milliseconds(CHECK_DISKINFO_TIME_MS),
287 [this]() {
288 return terminate_;
289 }
290 );
291
292 if (terminate_) {
293 break;
294 }
295 }
296 }
297
StartCheckDiskInfo()298 void CameraDumper::StartCheckDiskInfo()
299 {
300 {
301 std::unique_lock<std::mutex> l(terminateLock_);
302 if (terminate_ == false) {
303 CAMERA_LOGD("thread is already start");
304 return;
305 }
306 terminate_ = false;
307 }
308
309 handleThread_ = std::make_unique<std::thread>(&CameraDumper::ThreadWorkFun, this);
310 }
311
StopCheckDiskInfo()312 void CameraDumper::StopCheckDiskInfo()
313 {
314 {
315 std::unique_lock<std::mutex> l(terminateLock_);
316 if (terminate_ == true) {
317 CAMERA_LOGD("thread is already stop");
318 return;
319 }
320 terminate_ = true;
321 cv_.notify_one();
322 }
323 if (handleThread_ != nullptr && handleThread_->joinable()) {
324 handleThread_->join();
325 handleThread_ = nullptr;
326 }
327 }
328 } // namespace OHOS::Camera
329