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