/* * Copyright (c) 2024 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "surfaceconcurrent_fuzzer.h" #include #include #include "data_generate.h" #include "iconsumer_surface.h" #include "producer_surface_delegator.h" #include "surface.h" #include "surface_buffer.h" #include "surface_buffer_impl.h" #include using namespace g_fuzzCommon; namespace OHOS { namespace { const uint8_t* g_data = nullptr; size_t g_size = 0; size_t g_pos = 0; } /* * describe: get data from outside untrusted data(g_data) which size is according to sizeof(T) * tips: only support basic type */ template T GetData() { T object {}; size_t objectSize = sizeof(object); if (g_data == nullptr || objectSize > g_size - g_pos) { return object; } errno_t ret = memcpy_s(&object, objectSize, g_data + g_pos, objectSize); if (ret != EOK) { return {}; } g_pos += objectSize; return object; } static constexpr const uint32_t QUESIZE_RANGE = 10; static constexpr const uint32_t QUESIZE_MIN = 3; static constexpr const uint32_t BUFFERR_ROTATION_TIMES = 500; static constexpr const uint32_t BUFFERR_ROTATION_INTERVAL_MICRO_SECOND = 10; static constexpr const uint32_t CONCURRENCY_FUNCTION_TIMES = 500; static constexpr const uint32_t CONCURRENCY_FUNCTION_INTERVAL_MICRO_SECOND = 50; static constexpr const uint32_t ATTACHBUFFER_RETRY_TIMES = 10; BufferRequestConfig requestConfigTmp = { .width = 0x100, .height = 0x100, .strideAlignment = 0x8, .format = GRAPHIC_PIXEL_FMT_RGBA_8888, .usage = BUFFER_USAGE_CPU_READ | BUFFER_USAGE_CPU_WRITE | BUFFER_USAGE_MEM_DMA, .timeout = 1000, }; int g_releaseFence = -1; BufferFlushConfig flushConfig = { .damage = { .w = 0x100, .h = 0x100, }, }; std::atomic g_isCleanCacheFinish = false; std::atomic g_isGoBackGroundFinish = false; void producerBufferFunc(sptr pSurface) { for (uint32_t i = 0; i < BUFFERR_ROTATION_TIMES; i++) { usleep(BUFFERR_ROTATION_INTERVAL_MICRO_SECOND); sptr requestBuffer = nullptr; pSurface->RequestBuffer(requestBuffer, g_releaseFence, requestConfigTmp); usleep(BUFFERR_ROTATION_INTERVAL_MICRO_SECOND); pSurface->FlushBuffer(requestBuffer, -1, flushConfig); } std::cout<< pSurface->GetName() <<"prudecer finish"< cSurface) { int32_t flushFence; int64_t timestamp; OHOS::Rect damage; GSError ret; for (uint32_t i = 0; i < BUFFERR_ROTATION_TIMES; i++) { sptr acquireBuffer; usleep(BUFFERR_ROTATION_INTERVAL_MICRO_SECOND); ret = cSurface->AcquireBuffer(acquireBuffer, flushFence, timestamp, damage); usleep(BUFFERR_ROTATION_INTERVAL_MICRO_SECOND); cSurface->ReleaseBuffer(acquireBuffer, -1); } std::cout<< cSurface->GetName() <<" consumerFunc finish"< pSurface) { for (uint32_t i = 0; i < CONCURRENCY_FUNCTION_TIMES; i++) { usleep(CONCURRENCY_FUNCTION_INTERVAL_MICRO_SECOND); pSurface->CleanCache(true); } std::cout<< pSurface->GetName() <<" cleanCacheFunc finish"< pSurface) { for (uint32_t i = 0; i < CONCURRENCY_FUNCTION_TIMES; i++) { usleep(CONCURRENCY_FUNCTION_INTERVAL_MICRO_SECOND); pSurface->GoBackground(); } std::cout<< pSurface->GetName() <<" producerGoBackGroundFunc finish"< cSurface, sptr buffer) { uint32_t ret = 1; uint32_t count = ATTACHBUFFER_RETRY_TIMES; while (ret != GSERROR_OK && count-- > 0) { usleep(CONCURRENCY_FUNCTION_INTERVAL_MICRO_SECOND); ret = cSurface->AttachBufferToQueue(buffer); std::cout<< cSurface->GetName() <<"Comsumer call AttachBufferToQueue result: "<< ret <ReleaseBuffer(buffer, -1); } }; void producerAttachFunc(sptr pSurface, sptr buffer) { uint32_t ret = 1; uint32_t count = ATTACHBUFFER_RETRY_TIMES; while (ret != GSERROR_OK && count-- > 0) { usleep(CONCURRENCY_FUNCTION_INTERVAL_MICRO_SECOND); ret = pSurface->AttachBufferToQueue(buffer); std::cout<< pSurface->GetName() <<" producer call AttachBufferToQueue result: "<< ret <FlushBuffer(buffer, -1, flushConfig); } }; /* * CaseDescription: 1. preSetup: create two surface(surfaceA and surfaceB) * 2. operation: While surfaceA and surfaceB are rotating the buffer, the producer of surfaceA detaches * the buffer to surfaceB, and the producers of surfaceA and surfaceB perform cleanCache and * GoBackground operations. * Concurrent interface: * 1、RequestBuffer * 2、FlushBuffer * 3、AcquireBuffer * 4、ReleaseBuffer * 5、CleanCahce (producer) * 6、GoBackGround (producer) * 7、AttachBufferToQueue * 8、DetachBufferFromQueue (producer) * 3. result: buffer detach from surfaceA attach to surfaceB success multiple times without crash. */ void BufferRotationConcurrentWithAttachBufferAndDetachBufferAndCleanCacheAndGoBackground() { std::cout<<"start"< cSurfaceA = IConsumerSurface::Create(name); sptr consumerListener = new BufferConsumerListener(); cSurfaceA->RegisterConsumerListener(consumerListener); sptr producerClient = cSurfaceA->GetProducer(); sptr pSurfaceA = Surface::CreateSurfaceAsProducer(producerClient); // create surface B sptr cSurfaceB = IConsumerSurface::Create("SurfaceB"); sptr consumerListenerB = new BufferConsumerListener(); cSurfaceB->RegisterConsumerListener(consumerListenerB); sptr producerClientB = cSurfaceB->GetProducer(); sptr pSurfaceB = Surface::CreateSurfaceAsProducer(producerClientB); //init uint32_t queueSize = GetData(); queueSize = queueSize % QUESIZE_RANGE + QUESIZE_MIN; pSurfaceA->SetQueueSize(queueSize); pSurfaceB->SetQueueSize(queueSize); std::cout<<"Queue size: "<< queueSize < attachThreadList; uint32_t detachBufferTrigger = GetData(); detachBufferTrigger = (detachBufferTrigger % QUESIZE_RANGE) + 1; std::cout<<"detachBuffer Trigger: "<< detachBufferTrigger < requestBuffer = nullptr; auto ret = pSurfaceA->RequestBuffer(requestBuffer, g_releaseFence, requestConfigTmp); uint32_t count = 0; if (detachBufferTrigger == 0) { detachBufferTrigger++; } if (ret == GSERROR_OK && count++ % detachBufferTrigger == 0 && (!g_isCleanCacheFinish|| !g_isGoBackGroundFinish)) { usleep(BUFFERR_ROTATION_INTERVAL_MICRO_SECOND); ret = pSurfaceA->DetachBufferFromQueue(requestBuffer); if (ret != GSERROR_OK) { usleep(BUFFERR_ROTATION_INTERVAL_MICRO_SECOND); pSurfaceA->FlushBuffer(requestBuffer, -1, flushConfig); } bool surfaceBIsProducer = GetData(); if (surfaceBIsProducer) { std::thread attachThread(consumerAttachFunc, cSurfaceB, requestBuffer); attachThreadList.push_back(std::move(attachThread)); } else { std::thread attachThread(producerAttachFunc, pSurfaceB, requestBuffer); attachThreadList.push_back(std::move(attachThread)); } continue; } usleep(BUFFERR_ROTATION_INTERVAL_MICRO_SECOND); pSurfaceA->FlushBuffer(requestBuffer, -1, flushConfig); } // wait concurrent thread finish std::cout<< pSurfaceA->GetName() <<"prudecer finish"<