• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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