1 /*
2  * Copyright (c) 2021 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 "buffer_utils.h"
17 
18 #include <fcntl.h>
19 #include <unistd.h>
20 
21 #include "buffer_log.h"
22 #include "surface_buffer_impl.h"
23 
24 #include <securec.h>
25 #include <thread>
26 #include <fstream>
27 #include <sstream>
28 #include <sys/time.h>
29 
30 namespace OHOS {
ReadFileDescriptor(MessageParcel & parcel,int32_t & fd)31 void ReadFileDescriptor(MessageParcel &parcel, int32_t &fd)
32 {
33     fd = parcel.ReadInt32();
34     if (fd < 0) {
35         return;
36     }
37 
38     fd = parcel.ReadFileDescriptor();
39 }
40 
WriteFileDescriptor(MessageParcel & parcel,int32_t fd)41 void WriteFileDescriptor(MessageParcel &parcel, int32_t fd)
42 {
43     if (fd >= 0 && fcntl(fd, F_GETFL) == -1 && errno == EBADF) {
44         fd = -1;
45     }
46 
47     parcel.WriteInt32(fd);
48 
49     if (fd < 0) {
50         return;
51     }
52 
53     parcel.WriteFileDescriptor(fd);
54     close(fd);
55 }
56 
ReadRequestConfig(MessageParcel & parcel,BufferRequestConfig & config)57 void ReadRequestConfig(MessageParcel &parcel, BufferRequestConfig &config)
58 {
59     config.width = parcel.ReadInt32();
60     config.height = parcel.ReadInt32();
61     config.strideAlignment = parcel.ReadInt32();
62     config.format = parcel.ReadInt32();
63     config.usage = parcel.ReadUint64();
64     config.timeout = parcel.ReadInt32();
65     config.colorGamut = static_cast<GraphicColorGamut>(parcel.ReadInt32());
66     config.transform = static_cast<GraphicTransformType>(parcel.ReadInt32());
67 }
68 
WriteRequestConfig(MessageParcel & parcel,BufferRequestConfig const & config)69 void WriteRequestConfig(MessageParcel &parcel, BufferRequestConfig const & config)
70 {
71     parcel.WriteInt32(config.width);
72     parcel.WriteInt32(config.height);
73     parcel.WriteInt32(config.strideAlignment);
74     parcel.WriteInt32(config.format);
75     parcel.WriteUint64(config.usage);
76     parcel.WriteInt32(config.timeout);
77     parcel.WriteInt32(static_cast<int32_t>(config.colorGamut));
78     parcel.WriteInt32(static_cast<int32_t>(config.transform));
79 }
80 
ReadFlushConfig(MessageParcel & parcel,BufferFlushConfigWithDamages & config)81 void ReadFlushConfig(MessageParcel &parcel, BufferFlushConfigWithDamages &config)
82 {
83     uint32_t size = parcel.ReadUint32();
84     if (size == 0) {
85         BLOGE("ReadFlushConfig size is 0");
86         return;
87     }
88     if (size > SURFACE_PARCEL_SIZE_LIMIT) {
89         BLOGE("ReadFlushConfig size more than limit, size: %{public}u", size);
90         return;
91     }
92     config.damages.clear();
93     config.damages.reserve(size);
94     for (uint32_t i = 0; i < size; i++) {
95         Rect rect = {
96             .x = parcel.ReadInt32(),
97             .y = parcel.ReadInt32(),
98             .w = parcel.ReadInt32(),
99             .h = parcel.ReadInt32(),
100         };
101         config.damages.emplace_back(rect);
102     }
103     config.timestamp = parcel.ReadInt64();
104     config.desiredPresentTimestamp = parcel.ReadInt64();
105 }
106 
WriteFlushConfig(MessageParcel & parcel,BufferFlushConfigWithDamages const & config)107 void WriteFlushConfig(MessageParcel &parcel, BufferFlushConfigWithDamages const & config)
108 {
109     uint32_t size = config.damages.size();
110     if (size > SURFACE_PARCEL_SIZE_LIMIT) {
111         BLOGE("WriteFlushConfig size more than limit, size: %{public}u", size);
112         return;
113     }
114     parcel.WriteUint32(size);
115     for (const auto& rect : config.damages) {
116         parcel.WriteInt32(rect.x);
117         parcel.WriteInt32(rect.y);
118         parcel.WriteInt32(rect.w);
119         parcel.WriteInt32(rect.h);
120     }
121     parcel.WriteInt64(config.timestamp);
122     parcel.WriteInt64(config.desiredPresentTimestamp);
123 }
124 
ReadSurfaceBufferImpl(MessageParcel & parcel,uint32_t & sequence,sptr<SurfaceBuffer> & buffer)125 GSError ReadSurfaceBufferImpl(MessageParcel &parcel,
126                               uint32_t &sequence, sptr<SurfaceBuffer>& buffer)
127 {
128     GSError ret = GSERROR_OK;
129     sequence = parcel.ReadUint32();
130     if (parcel.ReadBool()) {
131         buffer = new SurfaceBufferImpl(sequence);
132         ret = buffer->ReadFromMessageParcel(parcel);
133     }
134     return ret;
135 }
136 
WriteSurfaceBufferImpl(MessageParcel & parcel,uint32_t sequence,const sptr<SurfaceBuffer> & buffer)137 void WriteSurfaceBufferImpl(MessageParcel &parcel,
138     uint32_t sequence, const sptr<SurfaceBuffer> &buffer)
139 {
140     parcel.WriteUint32(sequence);
141     parcel.WriteBool(buffer != nullptr);
142     if (buffer == nullptr) {
143         return;
144     }
145     buffer->WriteToMessageParcel(parcel);
146 }
147 
ReadVerifyAllocInfo(MessageParcel & parcel,std::vector<BufferVerifyAllocInfo> & infos)148 void ReadVerifyAllocInfo(MessageParcel &parcel, std::vector<BufferVerifyAllocInfo> &infos)
149 {
150     uint32_t size = parcel.ReadUint32();
151     if (size > SURFACE_PARCEL_SIZE_LIMIT) {
152         BLOGE("ReadVerifyAllocInfo size more than limit, size: %{public}u", size);
153         return;
154     }
155     infos.clear();
156     BufferVerifyAllocInfo info;
157     for (uint32_t index = 0; index < size; index++) {
158         info.width = parcel.ReadUint32();
159         info.height = parcel.ReadUint32();
160         info.usage = parcel.ReadUint64();
161         info.format = static_cast<GraphicPixelFormat>(parcel.ReadInt32());
162         infos.push_back(info);
163     }
164 }
165 
WriteVerifyAllocInfo(MessageParcel & parcel,const std::vector<BufferVerifyAllocInfo> & infos)166 void WriteVerifyAllocInfo(MessageParcel &parcel, const std::vector<BufferVerifyAllocInfo> &infos)
167 {
168     uint32_t size = infos.size();
169     if (size > SURFACE_PARCEL_SIZE_LIMIT) {
170         BLOGE("WriteVerifyAllocInfo size more than limit, size: %{public}u", size);
171         return;
172     }
173     parcel.WriteUint32(size);
174     for (const auto &info : infos) {
175         parcel.WriteUint32(info.width);
176         parcel.WriteUint32(info.height);
177         parcel.WriteUint64(info.usage);
178         parcel.WriteInt32(info.format);
179     }
180 }
181 
ReadHDRMetaData(MessageParcel & parcel,std::vector<GraphicHDRMetaData> & metaData)182 void ReadHDRMetaData(MessageParcel &parcel, std::vector<GraphicHDRMetaData> &metaData)
183 {
184     uint32_t size = parcel.ReadUint32();
185     if (size > SURFACE_PARCEL_SIZE_LIMIT) {
186         BLOGE("ReadHDRMetaData size more than limit, size: %{public}u", size);
187         return;
188     }
189     metaData.clear();
190     GraphicHDRMetaData data;
191     for (uint32_t index = 0; index < size; index++) {
192         data.key = static_cast<GraphicHDRMetadataKey>(parcel.ReadUint32());
193         data.value = parcel.ReadFloat();
194         metaData.push_back(data);
195     }
196 }
197 
WriteHDRMetaData(MessageParcel & parcel,const std::vector<GraphicHDRMetaData> & metaData)198 void WriteHDRMetaData(MessageParcel &parcel, const std::vector<GraphicHDRMetaData> &metaData)
199 {
200     uint32_t size = metaData.size();
201     if (size > SURFACE_PARCEL_SIZE_LIMIT) {
202         BLOGE("WriteHDRMetaData size more than limit, size: %{public}u", size);
203         return;
204     }
205     parcel.WriteUint32(size);
206     for (const auto &data : metaData) {
207         parcel.WriteUint32(static_cast<uint32_t>(data.key));
208         parcel.WriteFloat(data.value);
209     }
210 }
211 
ReadHDRMetaDataSet(MessageParcel & parcel,std::vector<uint8_t> & metaData)212 void ReadHDRMetaDataSet(MessageParcel &parcel, std::vector<uint8_t> &metaData)
213 {
214     uint32_t size = parcel.ReadUint32();
215     if (size > SURFACE_PARCEL_SIZE_LIMIT) {
216         BLOGE("ReadHDRMetaDataSet size more than limit, size: %{public}u", size);
217         return;
218     }
219     metaData.clear();
220     for (uint32_t index = 0; index < size; index++) {
221         uint8_t data = parcel.ReadUint8();
222         metaData.push_back(data);
223     }
224 }
225 
WriteHDRMetaDataSet(MessageParcel & parcel,const std::vector<uint8_t> & metaData)226 void WriteHDRMetaDataSet(MessageParcel &parcel, const std::vector<uint8_t> &metaData)
227 {
228     uint32_t size = metaData.size();
229     if (size > SURFACE_PARCEL_SIZE_LIMIT) {
230         BLOGE("WriteHDRMetaDataSet size more than limit, size: %{public}u", size);
231         return;
232     }
233     parcel.WriteUint32(size);
234     for (const auto &data : metaData) {
235         parcel.WriteUint8(data);
236     }
237 }
238 
ReadExtDataHandle(MessageParcel & parcel,sptr<SurfaceTunnelHandle> & handle)239 void ReadExtDataHandle(MessageParcel &parcel, sptr<SurfaceTunnelHandle> &handle)
240 {
241     if (handle == nullptr) {
242         BLOGE("handle is null");
243         return;
244     }
245     uint32_t reserveInts = parcel.ReadUint32();
246     if (reserveInts > SURFACE_PARCEL_SIZE_LIMIT) {
247         BLOGE("ReadExtDataHandle size more than limit, size: %{public}u", reserveInts);
248         return;
249     }
250     GraphicExtDataHandle *tunnelHandle = AllocExtDataHandle(reserveInts);
251     if (tunnelHandle == nullptr) {
252         BLOGE("AllocExtDataHandle failed");
253         return;
254     }
255     ReadFileDescriptor(parcel, tunnelHandle->fd);
256     for (uint32_t index = 0; index < reserveInts; index++) {
257         tunnelHandle->reserve[index] = parcel.ReadInt32();
258     }
259     if (handle->SetHandle(tunnelHandle) != GSERROR_OK) {
260         BLOGE("SetHandle failed");
261         FreeExtDataHandle(tunnelHandle);
262         return;
263     }
264     FreeExtDataHandle(tunnelHandle);
265 }
266 
WriteExtDataHandle(MessageParcel & parcel,const GraphicExtDataHandle * handle)267 void WriteExtDataHandle(MessageParcel &parcel, const GraphicExtDataHandle *handle)
268 {
269     if (handle == nullptr) {
270         BLOGE("handle is null");
271         return;
272     }
273     uint32_t reserveInts = handle->reserveInts;
274     if (reserveInts > SURFACE_PARCEL_SIZE_LIMIT) {
275         BLOGE("WriteExtDataHandle size more than limit, size: %{public}u", reserveInts);
276         return;
277     }
278     parcel.WriteUint32(reserveInts);
279     WriteFileDescriptor(parcel, handle->fd);
280     for (uint32_t index = 0; index < handle->reserveInts; index++) {
281         parcel.WriteInt32(handle->reserve[index]);
282     }
283 }
284 
CloneBuffer(uint8_t * dest,const uint8_t * src,size_t totalSize)285 void CloneBuffer(uint8_t* dest, const uint8_t* src, size_t totalSize)
286 {
287     size_t block_size = 1024 * 1024; // 1 MB block size
288     size_t num_blocks = totalSize / block_size;
289     size_t last_block_size = totalSize % block_size;
290 
291     // Obtain the number of parallelizable threads.
292     size_t num_threads = std::thread::hardware_concurrency();
293     num_threads = num_threads > 0 ? num_threads : 1;
294 
295     size_t blocks_per_thread = num_blocks / num_threads;
296     size_t remaining_blocks = num_blocks % num_threads;
297 
298     // Lambda function to copy a block of memory
299     auto copy_block = [&](uint8_t* current_dest, const uint8_t* current_src, size_t size) {
300         auto ret = memcpy_s(current_dest, size, current_src, size);
301         if (ret != 0) {
302             BLOGE("memcpy_s ret:%{public}d", static_cast<int>(ret));
303         }
304     };
305 
306     // Vector to store threads
307     std::vector<std::thread> threads;
308     uint8_t* current_dest = dest;
309     const uint8_t* current_src = src;
310 
311     // Create threads and copy blocks of memory
312     for (size_t i = 0; i < num_threads; ++i) {
313         size_t blocks_to_copy = blocks_per_thread + (i < remaining_blocks ? 1 : 0);
314         size_t length_to_copy = blocks_to_copy * block_size;
315 
316         threads.emplace_back(copy_block, current_dest, current_src, length_to_copy);
317 
318         current_dest += length_to_copy;
319         current_src += length_to_copy;
320     }
321 
322     if (last_block_size > 0) {
323         threads.emplace_back(copy_block, current_dest, current_src, last_block_size);
324     }
325 
326     // Wait for all threads to finish
327     for (auto& th : threads) {
328         if (th.joinable()) {
329             th.join();
330         }
331     }
332 }
333 
WriteToFile(std::string prefixPath,std::string pid,void * dest,size_t size,int32_t format,int32_t width,int32_t height,const std::string name)334 void WriteToFile(std::string prefixPath, std::string pid, void* dest, size_t size, int32_t format, int32_t width,
335     int32_t height, const std::string name)
336 {
337     struct timeval now;
338     gettimeofday(&now, nullptr);
339     constexpr int secToUsec = 1000 * 1000;
340     int64_t nowVal = (int64_t)now.tv_sec * secToUsec + (int64_t)now.tv_usec;
341 
342     std::stringstream ss;
343     ss << prefixPath << pid << "_" << name << "_" << nowVal << "_" << format << "_"
344         << width << "x" << height << ".raw";
345 
346     // Open the file for writing in binary mode
347     std::ofstream rawDataFile(ss.str(), std::ofstream::binary);
348     if (!rawDataFile.good()) {
349         BLOGE("open failed: (%{public}d)%{public}s", errno, strerror(errno));
350         free(dest);
351         return;
352     }
353 
354     // Write the data to the file
355     rawDataFile.write(static_cast<const char *>(dest), size);
356     rawDataFile.flush();
357     rawDataFile.close();
358 
359     // Free the memory allocated for the data
360     free(dest);
361 }
362 
DumpToFileAsync(pid_t pid,std::string name,sptr<SurfaceBuffer> & buffer)363 GSError DumpToFileAsync(pid_t pid, std::string name, sptr<SurfaceBuffer> &buffer)
364 {
365     bool rsDumpFlag = access("/data/bq_dump", F_OK) == 0;
366     bool appDumpFlag = access("/data/storage/el1/base/bq_dump", F_OK) == 0;
367     if (!rsDumpFlag && !appDumpFlag) {
368         return GSERROR_OK;
369     }
370 
371     if (buffer == nullptr) {
372         BLOGE("buffer is a nullptr.");
373         return GSERROR_INVALID_ARGUMENTS;
374     }
375 
376     size_t size = buffer->GetSize();
377     if (size > 0) {
378         uint8_t* src = static_cast<uint8_t*>(buffer->GetVirAddr());
379 
380         if (src == nullptr) {
381             BLOGE("src is a nullptr.");
382             return GSERROR_INVALID_ARGUMENTS;
383         }
384 
385         uint8_t* dest = static_cast<uint8_t*>(malloc(size));
386         if (dest != nullptr) {
387             // Copy through multithreading
388             CloneBuffer(dest, src, size);
389 
390             std::string prefixPath = "/data/bq_";
391             if (appDumpFlag) {
392                 // Is app texture export
393                 prefixPath = "/data/storage/el1/base/bq_";
394             }
395 
396             // create dump thread,async export file
397             std::thread file_writer(WriteToFile, prefixPath, std::to_string(pid), dest, size, buffer->GetFormat(),
398                 buffer->GetWidth(), buffer->GetHeight(), name);
399             file_writer.detach();
400         } else {
401             BLOGE("dest is a nullptr.");
402             return GSERROR_INTERNAL;
403         }
404     } else {
405         BLOGE("BufferDump buffer size(%{public}zu) error.", size);
406         return GSERROR_INTERNAL;
407     }
408 
409     return GSERROR_OK;
410 }
411 } // namespace OHOS
412