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