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