• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2024 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 "surfaceconcurrent_fuzzer.h"
17 
18 #include <securec.h>
19 #include <atomic>
20 
21 #include "data_generate.h"
22 #include "iconsumer_surface.h"
23 #include "producer_surface_delegator.h"
24 #include "surface.h"
25 #include "surface_buffer.h"
26 #include "surface_buffer_impl.h"
27 #include <iostream>
28 
29 using namespace g_fuzzCommon;
30 namespace OHOS {
31     namespace {
32         const uint8_t* g_data = nullptr;
33         size_t g_size = 0;
34         size_t g_pos = 0;
35     }
36 
37     /*
38     * describe: get data from outside untrusted data(g_data) which size is according to sizeof(T)
39     * tips: only support basic type
40     */
41     template<class T>
GetData()42     T GetData()
43     {
44         T object {};
45         size_t objectSize = sizeof(object);
46         if (g_data == nullptr || objectSize > g_size - g_pos) {
47             return object;
48         }
49         errno_t ret = memcpy_s(&object, objectSize, g_data + g_pos, objectSize);
50         if (ret != EOK) {
51             return {};
52         }
53         g_pos += objectSize;
54         return object;
55     }
56     static constexpr const uint32_t QUESIZE_RANGE = 10;
57     static constexpr const uint32_t QUESIZE_MIN = 3;
58     static constexpr const uint32_t BUFFERR_ROTATION_TIMES = 500;
59     static constexpr const uint32_t BUFFERR_ROTATION_INTERVAL_MICRO_SECOND = 10;
60     static constexpr const uint32_t CONCURRENCY_FUNCTION_TIMES = 500;
61     static constexpr const uint32_t CONCURRENCY_FUNCTION_INTERVAL_MICRO_SECOND = 50;
62     static constexpr const uint32_t ATTACHBUFFER_RETRY_TIMES = 10;
63     BufferRequestConfig requestConfigTmp = {
64         .width = 0x100,
65         .height = 0x100,
66         .strideAlignment = 0x8,
67         .format = GRAPHIC_PIXEL_FMT_RGBA_8888,
68         .usage = BUFFER_USAGE_CPU_READ | BUFFER_USAGE_CPU_WRITE | BUFFER_USAGE_MEM_DMA,
69         .timeout = 1000,
70     };
71     int g_releaseFence = -1;
72     BufferFlushConfig flushConfig = {
73         .damage = {
74             .w = 0x100,
75             .h = 0x100,
76         },
77     };
78     std::atomic<bool> g_isCleanCacheFinish = false;
79     std::atomic<bool> g_isGoBackGroundFinish = false;
80 
producerBufferFunc(sptr<Surface> pSurface)81     void producerBufferFunc(sptr<Surface> pSurface)
82     {
83         for (uint32_t i = 0; i < BUFFERR_ROTATION_TIMES; i++) {
84             usleep(BUFFERR_ROTATION_INTERVAL_MICRO_SECOND);
85             sptr<SurfaceBuffer> requestBuffer = nullptr;
86             pSurface->RequestBuffer(requestBuffer, g_releaseFence, requestConfigTmp);
87             usleep(BUFFERR_ROTATION_INTERVAL_MICRO_SECOND);
88             pSurface->FlushBuffer(requestBuffer, -1, flushConfig);
89         }
90         std::cout<< pSurface->GetName() <<"prudecer finish"<<std::endl;
91     };
92 
consumerBufferFunc(sptr<IConsumerSurface> cSurface)93     void consumerBufferFunc(sptr<IConsumerSurface> cSurface)
94     {
95         int32_t flushFence;
96         int64_t timestamp;
97         OHOS::Rect damage;
98         GSError ret;
99         for (uint32_t i = 0; i < BUFFERR_ROTATION_TIMES; i++) {
100             sptr<SurfaceBuffer> acquireBuffer;
101             usleep(BUFFERR_ROTATION_INTERVAL_MICRO_SECOND);
102             ret = cSurface->AcquireBuffer(acquireBuffer, flushFence, timestamp, damage);
103             usleep(BUFFERR_ROTATION_INTERVAL_MICRO_SECOND);
104             cSurface->ReleaseBuffer(acquireBuffer, -1);
105         }
106         std::cout<< cSurface->GetName() <<" consumerFunc finish"<<std::endl;
107     }
108 
cleanCacheFunc(sptr<Surface> pSurface)109     void cleanCacheFunc(sptr<Surface> pSurface)
110     {
111         for (uint32_t i = 0; i < CONCURRENCY_FUNCTION_TIMES; i++) {
112             usleep(CONCURRENCY_FUNCTION_INTERVAL_MICRO_SECOND);
113             pSurface->CleanCache(true);
114         }
115         std::cout<< pSurface->GetName() <<" cleanCacheFunc finish"<<std::endl;
116     };
117 
producerGoBackGroundFunc(sptr<Surface> pSurface)118     void producerGoBackGroundFunc(sptr<Surface> pSurface)
119     {
120         for (uint32_t i = 0; i < CONCURRENCY_FUNCTION_TIMES; i++) {
121             usleep(CONCURRENCY_FUNCTION_INTERVAL_MICRO_SECOND);
122             pSurface->GoBackground();
123         }
124         std::cout<< pSurface->GetName() <<" producerGoBackGroundFunc finish"<<std::endl;
125     };
126 
consumerAttachFunc(sptr<IConsumerSurface> cSurface,sptr<SurfaceBuffer> buffer)127     void consumerAttachFunc(sptr<IConsumerSurface> cSurface, sptr<SurfaceBuffer> buffer)
128     {
129         uint32_t ret = 1;
130         uint32_t count = ATTACHBUFFER_RETRY_TIMES;
131         while (ret != GSERROR_OK && count-- > 0) {
132             usleep(CONCURRENCY_FUNCTION_INTERVAL_MICRO_SECOND);
133             ret = cSurface->AttachBufferToQueue(buffer);
134             std::cout<< cSurface->GetName() <<"Comsumer call AttachBufferToQueue result: "<< ret <<std::endl;
135             ret = cSurface->ReleaseBuffer(buffer, -1);
136         }
137     };
138 
producerAttachFunc(sptr<Surface> pSurface,sptr<SurfaceBuffer> buffer)139     void producerAttachFunc(sptr<Surface> pSurface, sptr<SurfaceBuffer> buffer)
140     {
141         uint32_t ret = 1;
142         uint32_t count = ATTACHBUFFER_RETRY_TIMES;
143         while (ret != GSERROR_OK && count-- > 0) {
144             usleep(CONCURRENCY_FUNCTION_INTERVAL_MICRO_SECOND);
145             ret = pSurface->AttachBufferToQueue(buffer);
146             std::cout<< pSurface->GetName() <<" producer call AttachBufferToQueue result: "<< ret <<std::endl;
147             ret = pSurface->FlushBuffer(buffer, -1, flushConfig);
148         }
149     };
150 
151 /*
152 * CaseDescription: 1. preSetup: create two surface(surfaceA and surfaceB)
153 *                  2. operation: While surfaceA and surfaceB are rotating the buffer, the producer of surfaceA detaches
154 *                     the buffer to surfaceB, and the producers of surfaceA and surfaceB perform cleanCache and
155 *                     GoBackground operations.
156 *                     Concurrent interface:
157 *                     1、RequestBuffer
158 *                     2、FlushBuffer
159 *                     3、AcquireBuffer
160 *                     4、ReleaseBuffer
161 *                     5、CleanCahce (producer)
162 *                     6、GoBackGround (producer)
163 *                     7、AttachBufferToQueue
164 *                     8、DetachBufferFromQueue (producer)
165 *                  3. result: buffer detach from surfaceA attach to surfaceB success multiple times without crash.
166 */
BufferRotationConcurrentWithAttachBufferAndDetachBufferAndCleanCacheAndGoBackground()167     void BufferRotationConcurrentWithAttachBufferAndDetachBufferAndCleanCacheAndGoBackground()
168     {
169         std::cout<<"start"<<std::endl;
170         // create surface A
171         std::string name = GetStringFromData(STR_LEN);
172         sptr<IConsumerSurface> cSurfaceA = IConsumerSurface::Create(name);
173         sptr<IBufferConsumerListener> consumerListener = new BufferConsumerListener();
174         cSurfaceA->RegisterConsumerListener(consumerListener);
175         sptr<IBufferProducer> producerClient = cSurfaceA->GetProducer();
176         sptr<Surface> pSurfaceA = Surface::CreateSurfaceAsProducer(producerClient);
177 
178         // create surface B
179         sptr<IConsumerSurface> cSurfaceB = IConsumerSurface::Create("SurfaceB");
180         sptr<IBufferConsumerListener> consumerListenerB = new BufferConsumerListener();
181         cSurfaceB->RegisterConsumerListener(consumerListenerB);
182         sptr<IBufferProducer> producerClientB = cSurfaceB->GetProducer();
183         sptr<Surface> pSurfaceB = Surface::CreateSurfaceAsProducer(producerClientB);
184 
185         //init
186         uint32_t queueSize = GetData<uint32_t>();
187         queueSize = queueSize % QUESIZE_RANGE + QUESIZE_MIN;
188         pSurfaceA->SetQueueSize(queueSize);
189         pSurfaceB->SetQueueSize(queueSize);
190         std::cout<<"Queue size: "<< queueSize <<std::endl;
191 
192         //create concurrent thread
193         g_isCleanCacheFinish= false;
194         g_isGoBackGroundFinish = false;
195         std::thread consumerThread(consumerBufferFunc, cSurfaceA);
196         std::thread consumerThreadB(consumerBufferFunc, cSurfaceB);
197         std::thread cleanCacheThread(cleanCacheFunc, pSurfaceA);
198         std::thread cleanCacheThreadB(cleanCacheFunc, pSurfaceB);
199         std::thread goBackgroundThread(producerGoBackGroundFunc, pSurfaceA);
200         std::thread goBackgroundThreadB(producerGoBackGroundFunc, pSurfaceB);
201         std::thread producerThreadB(producerBufferFunc, pSurfaceB);
202 
203         std::vector<std::thread> attachThreadList;
204         uint32_t detachBufferTrigger = GetData<uint32_t>();
205         detachBufferTrigger = (detachBufferTrigger % QUESIZE_RANGE) + 1;
206         std::cout<<"detachBuffer Trigger: "<< detachBufferTrigger <<std::endl;
207         for (uint32_t i = 0; i < CONCURRENCY_FUNCTION_TIMES; i++) {
208             usleep(BUFFERR_ROTATION_INTERVAL_MICRO_SECOND);
209             sptr<SurfaceBuffer> requestBuffer = nullptr;
210             auto ret = pSurfaceA->RequestBuffer(requestBuffer, g_releaseFence, requestConfigTmp);
211             uint32_t count = 0;
212             if (detachBufferTrigger == 0) {
213                 detachBufferTrigger++;
214             }
215             if (ret == GSERROR_OK && count++ % detachBufferTrigger == 0
216                 && (!g_isCleanCacheFinish|| !g_isGoBackGroundFinish)) {
217                 usleep(BUFFERR_ROTATION_INTERVAL_MICRO_SECOND);
218                 ret = pSurfaceA->DetachBufferFromQueue(requestBuffer);
219                 if (ret != GSERROR_OK) {
220                     usleep(BUFFERR_ROTATION_INTERVAL_MICRO_SECOND);
221                     pSurfaceA->FlushBuffer(requestBuffer, -1, flushConfig);
222                 }
223                 bool surfaceBIsProducer = GetData<bool>();
224                 if (surfaceBIsProducer) {
225                     std::thread attachThread(consumerAttachFunc, cSurfaceB, requestBuffer);
226                     attachThreadList.push_back(std::move(attachThread));
227                 } else {
228                     std::thread attachThread(producerAttachFunc, pSurfaceB, requestBuffer);
229                     attachThreadList.push_back(std::move(attachThread));
230                 }
231                 continue;
232             }
233             usleep(BUFFERR_ROTATION_INTERVAL_MICRO_SECOND);
234             pSurfaceA->FlushBuffer(requestBuffer, -1, flushConfig);
235         }
236 
237         // wait concurrent thread finish
238         std::cout<< pSurfaceA->GetName() <<"prudecer finish"<<std::endl;
239         for (auto& attachThread : attachThreadList) {
240             if (attachThread.joinable()) {
241                 attachThread.join();
242             }
243         }
244         consumerThread.join();
245         cleanCacheThread.join();
246         goBackgroundThread.join();
247         consumerThreadB.join();
248         cleanCacheThreadB.join();
249         goBackgroundThreadB.join();
250         producerThreadB.join();
251         pSurfaceA = nullptr;
252         producerClient = nullptr;
253         cSurfaceA = nullptr;
254         pSurfaceB = nullptr;
255         producerClientB = nullptr;
256         cSurfaceB = nullptr;
257         std::cout<<"end"<<std::endl;
258     }
259 
DoSomethingInterestingWithMyAPI(const uint8_t * data,size_t size)260     bool DoSomethingInterestingWithMyAPI(const uint8_t* data, size_t size)
261     {
262         if (data == nullptr) {
263             return false;
264         }
265         // initialize
266         g_data = data;
267         g_size = size;
268         BufferRotationConcurrentWithAttachBufferAndDetachBufferAndCleanCacheAndGoBackground();
269         return true;
270     }
271 } // namespace OHOS
272 
273 /* Fuzzer entry point */
LLVMFuzzerTestOneInput(const uint8_t * data,size_t size)274 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
275 {
276     /* Run your code on data */
277     OHOS::DoSomethingInterestingWithMyAPI(data, size);
278     return 0;
279 }
280 
281