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