• 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 <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