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