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