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