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