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 30namespace OHOS { 31namespace { 32constexpr size_t BLOCK_SIZE = 1024 * 1024; // 1 MB block size 33} 34void 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 44GSError 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 64void 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 82GSError 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 94GSError 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 121GSError 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 147GSError 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 159GSError 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 174void 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 192GSError 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 211GSError 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 228GSError 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 246GSError 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 261GSError 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 279GSError 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 308GSError 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 334void 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 385void 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 418GSError 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