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