• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "camera_dump.h"
17 
18 #include <sys/time.h>
19 #include <unistd.h>
20 #include <fstream>
21 #include <sstream>
22 #include <cstdio>
23 #include <iostream>
24 #include <cstdlib>
25 #include <regex>
26 
27 #include "camera.h"
28 #include "v1_0/vdi_types.h"
29 
30 using namespace std;
31 
32 namespace OHOS::Camera {
33 const std::string DUMP_PATH = "/data/local/tmp/";
34 const std::string DUMP_CONFIG_PATH = "/data/local/tmp/dump.config";
35 constexpr uint32_t ARGS_MAX_NUM = 5;
36 constexpr uint32_t MAX_USAGE_RATE = 70;
37 constexpr int32_t CHECK_DISKINFO_TIME_MS = 10000;
38 const uint32_t TITLEINFO_ARRAY_SIZE = 200;
39 
40 const char *g_cameraDumpHelp =
41     " Camera manager dump options:\n"
42     "     -h: camera dump help\n"
43     "     -m: start dump metadata\n"
44     "     -b: start dump buffer\n"
45     "     -o: start dump start\n"
46     "     -e: exit all dump\n";
47 
48 std::map<DumpType, bool> g_dumpInfoMap = {
49     {MedataType, false},
50     {BufferType, false},
51     {OpenType, false}
52 };
53 
54 std::map<std::string, std::string> g_dumpToolMap = {
55     {ENABLE_DQ_BUFFER_DUMP, "false"},
56     {ENABLE_UVC_NODE, "false"},
57     {ENABLE_UVC_NODE_CONVERTED, "false"},
58     {ENABLE_EXIF_NODE_CONVERTED, "false"},
59     {ENABLE_FACE_NODE_CONVERTED, "false"},
60     {ENABLE_FORK_NODE_CONVERTED, "false"},
61     {ENABLE_RKFACE_NODE_CONVERTED, "false"},
62     {ENABLE_RKEXIF_NODE_CONVERTED, "false"},
63     {ENABLE_CODEC_NODE_CONVERTED, "false"},
64     {ENABLE_RKCODEC_NODE_CONVERTED, "false"},
65     {ENABLE_STREAM_TUNNEL, "false"},
66     {ENABLE_METADATA, "false"},
67     {PREVIEW_INTERVAL, "1"},
68     {CAPTURE_INTERVAL, "1"}
69 };
70 
~CameraDumper()71 CameraDumper::~CameraDumper()
72 {
73     StopCheckDiskInfo();
74 }
75 
DumpStart()76 bool CameraDumper::DumpStart()
77 {
78     if (!IsDumpOpened(OpenType)) {
79         return false;
80     }
81     std::stringstream mkdirCmd;
82     mkdirCmd << "mkdir -p " << DUMP_PATH;
83     system(mkdirCmd.str().c_str());
84 
85     ReadDumpConfig();
86     return true;
87 }
88 
ReadDumpConfig()89 bool CameraDumper::ReadDumpConfig()
90 {
91     std::stringstream ss;
92     ss << DUMP_CONFIG_PATH;
93     std::string configPath = ss.str();
94     if (access(configPath.c_str(), R_OK) != 0) {
95         CAMERA_LOGE("dump config file <%{public}s> not exist or not readable", configPath.c_str());
96         return false;
97     }
98     std::ifstream ifs;
99     ifs.open(configPath, std::ios::in);
100     if (!ifs) {
101         CAMERA_LOGE("open dump config file <%{public}s> failed, error: %{public}s",
102             configPath.c_str(), std::strerror(errno));
103         return false;
104     }
105 
106     std::string str;
107     while (!ifs.eof()) {
108         if (ifs >> str) {
109             istringstream istr(str);
110             std::string strTemp;
111             vector<std::string> strVector;
112             while (getline(istr, strTemp, '=')) {
113                 strVector.push_back(strTemp);
114             }
115             g_dumpToolMap[strVector[0]] = strVector[1];
116         }
117     }
118 
119     ifs.close();
120     return true;
121 }
122 
IsDumpCommandOpened(std::string type)123 bool CameraDumper::IsDumpCommandOpened(std::string type)
124 {
125     std::lock_guard<std::mutex> l(dumpStateLock_);
126     if (g_dumpToolMap.find(type) != g_dumpToolMap.end() && g_dumpToolMap[type] == "true") {
127         return true;
128     }
129     return false;
130 }
131 
DumpBuffer(std::string name,std::string type,const std::shared_ptr<IBuffer> & buffer,uint32_t width,uint32_t height)132 bool CameraDumper::DumpBuffer(std::string name, std::string type, const std::shared_ptr<IBuffer>& buffer,
133     uint32_t width, uint32_t height)
134 {
135     if (!IsDumpOpened(OpenType) || !IsDumpCommandOpened(type) || (buffer == nullptr)) {
136         return false;
137     }
138     uint32_t defaultWidth = (width == 0) ? buffer->GetCurWidth() : width;
139     uint32_t defaultHeight = (height == 0) ? buffer->GetCurHeight() : height;
140     void* srcAddr = buffer->GetIsValidDataInSurfaceBuffer() ? buffer->GetSuffaceBufferAddr() : buffer->GetVirAddress();
141     uint32_t size = buffer->GetIsValidDataInSurfaceBuffer() ? buffer->GetSuffaceBufferSize() : buffer->GetSize();
142     const std::string DqBufferName = "DQBuffer";
143     if (name != DqBufferName) {
144         size = buffer->GetEsFrameInfo().size > 0 ? static_cast<uint32_t>(buffer->GetEsFrameInfo().size) : size;
145     }
146 
147     std::stringstream ss;
148     std::string fileName;
149     ss << name.c_str() << "_captureId[" << buffer->GetCaptureId() << "]_streamId[" << buffer->GetStreamId() <<
150         "]_width[" << defaultWidth << "]_height[" << defaultHeight;
151 
152     int32_t previewInterval = 1;
153     std::istringstream ssPreview(g_dumpToolMap[PREVIEW_INTERVAL]);
154     ssPreview >> previewInterval;
155 
156     int32_t captureInterval = 1;
157     std::istringstream ssVideo(g_dumpToolMap[CAPTURE_INTERVAL]);
158     ssVideo >> captureInterval;
159 
160     ++dumpCount_;
161     if (buffer->GetEncodeType() == VDI::Camera::V1_0::ENCODE_TYPE_JPEG) {
162         if (dumpCount_ % captureInterval != 0) {
163             return true;
164         }
165         ss << "]_" << GetCurrentLocalTimeStamp();
166         ss >> fileName;
167         fileName += ".jpeg";
168     } else if (buffer->GetEncodeType() == VDI::Camera::V1_0::ENCODE_TYPE_H264) {
169 #ifdef CAMERA_BUILT_ON_USB
170         ss << "]_" << GetCurrentLocalTimeStamp();
171         ss >> fileName;
172         fileName += "_umpVideo.yuv";
173 #else
174         fileName += "dumpVideo.h264";
175 #endif
176     } else {
177         if (dumpCount_ % previewInterval != 0) {
178             return true;
179         }
180 
181         ss << "]_" << GetCurrentLocalTimeStamp();
182         ss >> fileName;
183         fileName += (buffer->GetCurFormat() == CAMERA_FORMAT_BLOB ? ".jpeg" : ".yuv");
184     }
185     return SaveDataToFile(fileName.c_str(), srcAddr, size);
186 }
187 
DumpMetadata(std::string name,std::string type,const std::shared_ptr<CameraMetadata> & metadata)188 bool CameraDumper::DumpMetadata(std::string name, std::string type,
189     const std::shared_ptr<CameraMetadata>& metadata)
190 {
191     if (metadata == nullptr) {
192         CAMERA_LOGE("metadata is nullptr");
193         return false;
194     }
195 
196     if (!IsDumpOpened(OpenType) || !IsDumpCommandOpened(type)) {
197         return false;
198     }
199 
200     common_metadata_header_t *data = metadata->get();
201     if (data == nullptr) {
202         CAMERA_LOGE("data is nullptr");
203         return false;
204     }
205     std::string metaStr = FormatCameraMetadataToString(data);
206     if (metaStr.size() == 0) {
207         CAMERA_LOGE("metaStr.size is 0");
208         return true;
209     }
210     std::stringstream ss;
211     ss << GetCurrentLocalTimeStamp() << "_" << name << ".meta";
212 
213     return SaveDataToFile(ss.str().c_str(), metaStr.c_str(), metaStr.size());
214 }
215 
UpdateDumpMode(DumpType type,bool isDump,HdfSBuf * reply)216 void CameraDumper::UpdateDumpMode(DumpType type, bool isDump, HdfSBuf *reply)
217 {
218     std::string upRetStr;
219     {
220         std::lock_guard<std::mutex> l(dumpStateLock_);
221         auto it = g_dumpInfoMap.find(type);
222         if (it != g_dumpInfoMap.end()) {
223             g_dumpInfoMap[type] = isDump;
224             upRetStr += " set dump mode success!\n";
225         }
226     }
227 
228     if (reply != nullptr) {
229         (void)HdfSbufWriteString(reply, upRetStr.c_str());
230     }
231 
232     if (isDump) {
233         StartCheckDiskInfo();
234     } else {
235         StopCheckDiskInfo();
236     }
237 }
238 
IsDumpOpened(DumpType type)239 bool CameraDumper::IsDumpOpened(DumpType type)
240 {
241     std::lock_guard<std::mutex> l(dumpStateLock_);
242     if (g_dumpInfoMap.find(type) != g_dumpInfoMap.end() && g_dumpInfoMap[type]) {
243         return true;
244     }
245     return false;
246 }
247 
SaveDataToFile(const char * fileName,const void * data,uint32_t size)248 bool CameraDumper::SaveDataToFile(const char *fileName, const void *data, uint32_t size)
249 {
250     CAMERA_LOGI("save dump file <%{public}s> begin, size: %{public}d", fileName, size);
251     std::stringstream mkdirCmd;
252     mkdirCmd << "mkdir -p " << DUMP_PATH;
253     system(mkdirCmd.str().c_str());
254     if (access(DUMP_PATH.c_str(), F_OK) != 0 || access(DUMP_PATH.c_str(), W_OK) != 0) {
255         CAMERA_LOGE("dump path <%{public}s> not exist, error: %{public}s", DUMP_PATH.c_str(), std::strerror(errno));
256         return false;
257     }
258 
259     std::stringstream ss;
260     ss << DUMP_PATH << fileName;
261     std::ofstream ofs(ss.str(), std::ios::app);
262 
263     if (!ofs.good()) {
264         CAMERA_LOGE("open dump file <%{public}s> failed, error: %{public}s", ss.str().c_str(), std::strerror(errno));
265         return false;
266     }
267 
268     ofs.write(static_cast<const char *>(data), size);
269     ofs.close();
270 
271     return true;
272 }
273 
GetCurrentLocalTimeStamp()274 uint64_t CameraDumper::GetCurrentLocalTimeStamp()
275 {
276     std::chrono::time_point<std::chrono::system_clock, std::chrono::milliseconds> tp =
277         std::chrono::time_point_cast<std::chrono::milliseconds>(std::chrono::system_clock::now());
278     auto tmp = std::chrono::duration_cast<std::chrono::milliseconds>(tp.time_since_epoch());
279     return static_cast<uint64_t>(tmp.count());
280 }
281 
ShowDumpMenu(HdfSBuf * reply)282 void CameraDumper::ShowDumpMenu(HdfSBuf *reply)
283 {
284     if (reply != nullptr) {
285         (void)HdfSbufWriteString(reply, g_cameraDumpHelp);
286     }
287 }
288 
CameraHostDumpProcess(HdfSBuf * data,HdfSBuf * reply)289 void CameraDumper::CameraHostDumpProcess(HdfSBuf *data, HdfSBuf *reply)
290 {
291     if (data == nullptr || reply == nullptr) {
292         CAMERA_LOGE("%{public}s is nullptr", (data == nullptr) ? "data" : "reply");
293         return;
294     }
295 
296     uint32_t argsNum;
297     if (!HdfSbufReadUint32(data, &argsNum)) {
298         CAMERA_LOGE("read argsNum failed!");
299         return;
300     }
301 
302     if (argsNum <= 0 || argsNum > ARGS_MAX_NUM) {
303         (void)HdfSbufWriteString(reply, g_cameraDumpHelp);
304         return;
305     }
306 
307     for (uint32_t i = 0; i < argsNum; i++) {
308         const char *value = HdfSbufReadString(data);
309         if (value == NULL) {
310             CAMERA_LOGE("arg is invalid i: %{public}u", i);
311             return;
312         }
313         if (strcmp(value, "-m") == 0) {
314             UpdateDumpMode(MedataType, true, reply);
315         } else if (strcmp(value, "-b") == 0) {
316             UpdateDumpMode(BufferType, true, reply);
317         } else if (strcmp(value, "-e") == 0) {
318             UpdateDumpMode(BufferType, false, reply);
319             UpdateDumpMode(MedataType, false, reply);
320         } else if (strcmp(value, "-o") == 0) {
321             UpdateDumpMode(OpenType, true, reply);
322         } else {
323             ShowDumpMenu(reply);
324         }
325     }
326 }
327 
CameraDumpEvent(HdfSBuf * data,HdfSBuf * reply)328 int32_t CameraDumpEvent(HdfSBuf *data, HdfSBuf *reply)
329 {
330     CameraDumper& dumper = CameraDumper::GetInstance();
331     dumper.CameraHostDumpProcess(data, reply);
332     return HDF_SUCCESS;
333 }
334 
CheckDiskInfo()335 void CameraDumper::CheckDiskInfo()
336 {
337     stringstream ss;
338     ss << "df " << DUMP_PATH;
339 
340     FILE *fp = popen(ss.str().c_str(), "r");
341     if (fp == NULL) {
342         CAMERA_LOGE("popen failed, cmd : %{public}s", ss.str().c_str());
343         return;
344     }
345 
346     char titleInfo[TITLEINFO_ARRAY_SIZE] = {0};
347     char resultInfo[TITLEINFO_ARRAY_SIZE] = {0};
348     fgets(titleInfo, sizeof(titleInfo) / sizeof(titleInfo[0]) - 1, fp);
349     fgets(resultInfo, sizeof(resultInfo) / sizeof(resultInfo[0]) - 1, fp);
350 
351     pclose(fp);
352 
353     std::string diskInfoStr(resultInfo);
354     istringstream str(diskInfoStr);
355     string out;
356     std::vector<std::string> infos;
357 
358     while (str >> out) {
359         infos.push_back(out);
360     }
361 
362     std::string userPerStr = infos[4].substr(0, infos[4].length() - 1);
363     uint32_t usePer = static_cast<uint32_t>(std::atoi(userPerStr.c_str()));
364     if (usePer >= MAX_USAGE_RATE) {
365         CAMERA_LOGE("dump use disk over the limit, stop dump");
366         std::lock_guard<std::mutex> l(dumpStateLock_);
367         for (auto it = g_dumpInfoMap.begin(); it != g_dumpInfoMap.end(); it++) {
368             it->second = false;
369         }
370     }
371 }
372 
ThreadWorkFun()373 void CameraDumper::ThreadWorkFun()
374 {
375     while (true) {
376         CheckDiskInfo();
377 
378         std::unique_lock<std::mutex> l(terminateLock_);
379         cv_.wait_for(l, std::chrono::milliseconds(CHECK_DISKINFO_TIME_MS),
380             [this]() {
381                 return terminate_;
382             }
383         );
384 
385         if (terminate_) {
386             break;
387         }
388     }
389 }
390 
StartCheckDiskInfo()391 void CameraDumper::StartCheckDiskInfo()
392 {
393     {
394         std::unique_lock<std::mutex> l(terminateLock_);
395         if (terminate_ == false) {
396             CAMERA_LOGD("thread is already start");
397             return;
398         }
399         terminate_ = false;
400     }
401 
402     handleThread_ = std::make_unique<std::thread>([this] { this->ThreadWorkFun(); });
403 }
404 
StopCheckDiskInfo()405 void CameraDumper::StopCheckDiskInfo()
406 {
407     {
408         std::unique_lock<std::mutex> l(terminateLock_);
409         if (terminate_ == true) {
410             CAMERA_LOGD("thread is already stop");
411             return;
412         }
413         terminate_ = true;
414         cv_.notify_one();
415     }
416     if (handleThread_ != nullptr && handleThread_->joinable()) {
417         handleThread_->join();
418         handleThread_ = nullptr;
419     }
420 }
421 
GetInstance()422 CameraDumper& CameraDumper::GetInstance()
423 {
424     static CameraDumper instance_;
425     return instance_;
426 }
427 } // namespace OHOS::Camera
428