| /* |
| * Copyright 2022 The Android Open Source Project |
| * |
| * 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 <android-base/stringprintf.h> |
| #include <gui/BufferQueueConsumer.h> |
| #include <gui/BufferQueueCore.h> |
| #include <gui/BufferQueueProducer.h> |
| #include <gui/bufferqueue/2.0/types.h> |
| #include <system/window.h> |
| |
| #include <libgui_fuzzer_utils.h> |
| |
| using namespace android; |
| using namespace hardware::graphics::bufferqueue; |
| using namespace V1_0::utils; |
| using namespace V2_0::utils; |
| |
| constexpr int32_t kMaxBytes = 256; |
| |
| constexpr int32_t kError[] = { |
| OK, NO_MEMORY, NO_INIT, BAD_VALUE, DEAD_OBJECT, INVALID_OPERATION, |
| TIMED_OUT, WOULD_BLOCK, UNKNOWN_ERROR, ALREADY_EXISTS, |
| }; |
| |
| constexpr int32_t kAPIConnection[] = { |
| BufferQueueCore::CURRENTLY_CONNECTED_API, |
| BufferQueueCore::NO_CONNECTED_API, |
| NATIVE_WINDOW_API_EGL, |
| NATIVE_WINDOW_API_CPU, |
| NATIVE_WINDOW_API_MEDIA, |
| NATIVE_WINDOW_API_CAMERA, |
| }; |
| |
| class BufferQueueFuzzer { |
| public: |
| BufferQueueFuzzer(const uint8_t* data, size_t size) : mFdp(data, size){}; |
| void process(); |
| |
| private: |
| void invokeTypes(); |
| void invokeH2BGraphicBufferV1(); |
| void invokeH2BGraphicBufferV2(); |
| void invokeBufferQueueConsumer(); |
| void invokeBufferQueueProducer(); |
| void invokeBlastBufferQueue(); |
| void invokeQuery(sp<BufferQueueProducer>); |
| void invokeQuery(sp<V1_0::utils::H2BGraphicBufferProducer>); |
| void invokeQuery(sp<V2_0::utils::H2BGraphicBufferProducer>); |
| void invokeAcquireBuffer(sp<BufferQueueConsumer>); |
| void invokeOccupancyTracker(sp<BufferQueueConsumer>); |
| sp<SurfaceControl> makeSurfaceControl(); |
| sp<BLASTBufferQueue> makeBLASTBufferQueue(sp<SurfaceControl>); |
| |
| FuzzedDataProvider mFdp; |
| }; |
| |
| class ManageResourceHandle { |
| public: |
| ManageResourceHandle(FuzzedDataProvider* fdp) { |
| mNativeHandle = native_handle_create(0 /*numFds*/, 1 /*numInts*/); |
| mShouldOwn = fdp->ConsumeBool(); |
| mStream = NativeHandle::create(mNativeHandle, mShouldOwn); |
| } |
| ~ManageResourceHandle() { |
| if (!mShouldOwn) { |
| native_handle_close(mNativeHandle); |
| native_handle_delete(mNativeHandle); |
| } |
| } |
| sp<NativeHandle> getStream() { return mStream; } |
| |
| private: |
| bool mShouldOwn; |
| sp<NativeHandle> mStream; |
| native_handle_t* mNativeHandle; |
| }; |
| |
| sp<SurfaceControl> BufferQueueFuzzer::makeSurfaceControl() { |
| sp<IBinder> handle; |
| const sp<FakeBnSurfaceComposerClient> testClient(new FakeBnSurfaceComposerClient()); |
| sp<SurfaceComposerClient> client = new SurfaceComposerClient(testClient); |
| sp<BnGraphicBufferProducer> producer; |
| uint32_t layerId = mFdp.ConsumeIntegral<uint32_t>(); |
| std::string layerName = base::StringPrintf("#%d", layerId); |
| return sp<SurfaceControl>::make(client, handle, layerId, layerName, |
| mFdp.ConsumeIntegral<int32_t>(), |
| mFdp.ConsumeIntegral<uint32_t>(), |
| mFdp.ConsumeIntegral<int32_t>(), |
| mFdp.ConsumeIntegral<uint32_t>(), |
| mFdp.ConsumeIntegral<uint32_t>()); |
| } |
| |
| sp<BLASTBufferQueue> BufferQueueFuzzer::makeBLASTBufferQueue(sp<SurfaceControl> surface) { |
| return sp<BLASTBufferQueue>::make(mFdp.ConsumeRandomLengthString(kMaxBytes), surface, |
| mFdp.ConsumeIntegral<uint32_t>(), |
| mFdp.ConsumeIntegral<uint32_t>(), |
| mFdp.ConsumeIntegral<int32_t>()); |
| } |
| |
| void BufferQueueFuzzer::invokeBlastBufferQueue() { |
| sp<SurfaceControl> surface = makeSurfaceControl(); |
| sp<BLASTBufferQueue> queue = makeBLASTBufferQueue(surface); |
| |
| BufferItem item; |
| queue->onFrameAvailable(item); |
| queue->onFrameReplaced(item); |
| uint64_t bufferId = mFdp.ConsumeIntegral<uint64_t>(); |
| queue->onFrameDequeued(bufferId); |
| queue->onFrameCancelled(bufferId); |
| |
| SurfaceComposerClient::Transaction next; |
| uint64_t frameNumber = mFdp.ConsumeIntegral<uint64_t>(); |
| queue->mergeWithNextTransaction(&next, frameNumber); |
| queue->applyPendingTransactions(frameNumber); |
| |
| queue->update(surface, mFdp.ConsumeIntegral<uint32_t>(), mFdp.ConsumeIntegral<uint32_t>(), |
| mFdp.ConsumeIntegral<int32_t>()); |
| queue->setFrameRate(mFdp.ConsumeFloatingPoint<float>(), mFdp.ConsumeIntegral<int8_t>(), |
| mFdp.ConsumeBool() /*shouldBeSeamless*/); |
| FrameTimelineInfo info; |
| queue->setFrameTimelineInfo(mFdp.ConsumeIntegral<uint64_t>(), info); |
| |
| ManageResourceHandle handle(&mFdp); |
| queue->setSidebandStream(handle.getStream()); |
| |
| queue->getLastTransformHint(); |
| queue->getLastAcquiredFrameNum(); |
| |
| CompositorTiming compTiming; |
| sp<Fence> previousFence = new Fence(memfd_create("pfd", MFD_ALLOW_SEALING)); |
| sp<Fence> gpuFence = new Fence(memfd_create("gfd", MFD_ALLOW_SEALING)); |
| FrameEventHistoryStats frameStats(frameNumber, gpuFence, compTiming, |
| mFdp.ConsumeIntegral<int64_t>(), |
| mFdp.ConsumeIntegral<int64_t>()); |
| std::vector<SurfaceControlStats> stats; |
| sp<Fence> presentFence = new Fence(memfd_create("fd", MFD_ALLOW_SEALING)); |
| SurfaceControlStats controlStats(surface, mFdp.ConsumeIntegral<int64_t>(), |
| mFdp.ConsumeIntegral<int64_t>(), presentFence, previousFence, |
| mFdp.ConsumeIntegral<uint32_t>(), frameStats, |
| mFdp.ConsumeIntegral<uint32_t>()); |
| stats.push_back(controlStats); |
| } |
| |
| void BufferQueueFuzzer::invokeQuery(sp<BufferQueueProducer> producer) { |
| int32_t value; |
| producer->query(mFdp.ConsumeIntegral<int32_t>(), &value); |
| } |
| |
| void BufferQueueFuzzer::invokeQuery(sp<V1_0::utils::H2BGraphicBufferProducer> producer) { |
| int32_t value; |
| producer->query(mFdp.ConsumeIntegral<int32_t>(), &value); |
| } |
| |
| void BufferQueueFuzzer::invokeQuery(sp<V2_0::utils::H2BGraphicBufferProducer> producer) { |
| int32_t value; |
| producer->query(mFdp.ConsumeIntegral<int32_t>(), &value); |
| } |
| |
| void BufferQueueFuzzer::invokeBufferQueueProducer() { |
| sp<BufferQueueCore> core(new BufferQueueCore()); |
| sp<BufferQueueProducer> producer(new BufferQueueProducer(core)); |
| const sp<android::IProducerListener> listener; |
| android::IGraphicBufferProducer::QueueBufferOutput output; |
| uint32_t api = mFdp.ConsumeIntegral<uint32_t>(); |
| producer->connect(listener, api, mFdp.ConsumeBool() /*producerControlledByApp*/, &output); |
| |
| sp<GraphicBuffer> buffer; |
| int32_t slot = mFdp.ConsumeIntegral<int32_t>(); |
| uint32_t maxBuffers = mFdp.ConsumeIntegral<uint32_t>(); |
| producer->requestBuffer(slot, &buffer); |
| producer->setMaxDequeuedBufferCount(maxBuffers); |
| producer->setAsyncMode(mFdp.ConsumeBool() /*async*/); |
| |
| android::IGraphicBufferProducer::QueueBufferInput input; |
| producer->attachBuffer(&slot, buffer); |
| producer->queueBuffer(slot, input, &output); |
| |
| int32_t format = mFdp.ConsumeIntegral<int32_t>(); |
| uint32_t width = mFdp.ConsumeIntegral<uint32_t>(); |
| uint32_t height = mFdp.ConsumeIntegral<uint32_t>(); |
| uint64_t usage = mFdp.ConsumeIntegral<uint64_t>(); |
| uint64_t outBufferAge; |
| FrameEventHistoryDelta outTimestamps; |
| sp<android::Fence> fence; |
| producer->dequeueBuffer(&slot, &fence, width, height, format, usage, &outBufferAge, |
| &outTimestamps); |
| producer->detachBuffer(slot); |
| producer->detachNextBuffer(&buffer, &fence); |
| producer->cancelBuffer(slot, fence); |
| |
| invokeQuery(producer); |
| |
| ManageResourceHandle handle(&mFdp); |
| producer->setSidebandStream(handle.getStream()); |
| |
| producer->allocateBuffers(width, height, format, usage); |
| producer->allowAllocation(mFdp.ConsumeBool() /*allow*/); |
| producer->setSharedBufferMode(mFdp.ConsumeBool() /*sharedBufferMode*/); |
| producer->setAutoRefresh(mFdp.ConsumeBool() /*autoRefresh*/); |
| producer->setLegacyBufferDrop(mFdp.ConsumeBool() /*drop*/); |
| producer->setAutoPrerotation(mFdp.ConsumeBool() /*autoPrerotation*/); |
| |
| producer->setGenerationNumber(mFdp.ConsumeIntegral<uint32_t>()); |
| producer->setDequeueTimeout(mFdp.ConsumeIntegral<uint32_t>()); |
| producer->disconnect(api); |
| } |
| |
| void BufferQueueFuzzer::invokeAcquireBuffer(sp<BufferQueueConsumer> consumer) { |
| BufferItem item; |
| consumer->acquireBuffer(&item, mFdp.ConsumeIntegral<uint32_t>(), |
| mFdp.ConsumeIntegral<uint64_t>()); |
| } |
| |
| void BufferQueueFuzzer::invokeOccupancyTracker(sp<BufferQueueConsumer> consumer) { |
| String8 outResult; |
| String8 prefix((mFdp.ConsumeRandomLengthString(kMaxBytes)).c_str()); |
| consumer->dumpState(prefix, &outResult); |
| |
| std::vector<OccupancyTracker::Segment> outHistory; |
| consumer->getOccupancyHistory(mFdp.ConsumeBool() /*forceFlush*/, &outHistory); |
| } |
| |
| void BufferQueueFuzzer::invokeBufferQueueConsumer() { |
| sp<BufferQueueCore> core(new BufferQueueCore()); |
| sp<BufferQueueConsumer> consumer(new BufferQueueConsumer(core)); |
| sp<android::IConsumerListener> listener; |
| consumer->consumerConnect(listener, mFdp.ConsumeBool() /*controlledByApp*/); |
| invokeAcquireBuffer(consumer); |
| |
| int32_t slot = mFdp.ConsumeIntegral<int32_t>(); |
| sp<GraphicBuffer> buffer = |
| new GraphicBuffer(mFdp.ConsumeIntegral<uint32_t>(), mFdp.ConsumeIntegral<uint32_t>(), |
| mFdp.ConsumeIntegral<int32_t>(), mFdp.ConsumeIntegral<uint32_t>(), |
| mFdp.ConsumeIntegral<uint64_t>()); |
| consumer->attachBuffer(&slot, buffer); |
| consumer->detachBuffer(slot); |
| |
| consumer->setDefaultBufferSize(mFdp.ConsumeIntegral<uint32_t>(), |
| mFdp.ConsumeIntegral<uint32_t>()); |
| consumer->setMaxBufferCount(mFdp.ConsumeIntegral<int32_t>()); |
| consumer->setMaxAcquiredBufferCount(mFdp.ConsumeIntegral<int32_t>()); |
| |
| String8 name((mFdp.ConsumeRandomLengthString(kMaxBytes)).c_str()); |
| consumer->setConsumerName(name); |
| consumer->setDefaultBufferFormat(mFdp.ConsumeIntegral<int32_t>()); |
| android_dataspace dataspace = |
| static_cast<android_dataspace>(mFdp.PickValueInArray(kDataspaces)); |
| consumer->setDefaultBufferDataSpace(dataspace); |
| |
| consumer->setTransformHint(mFdp.ConsumeIntegral<uint32_t>()); |
| consumer->setConsumerUsageBits(mFdp.ConsumeIntegral<uint64_t>()); |
| consumer->setConsumerIsProtected(mFdp.ConsumeBool() /*isProtected*/); |
| invokeOccupancyTracker(consumer); |
| |
| sp<Fence> releaseFence = new Fence(memfd_create("fd", MFD_ALLOW_SEALING)); |
| consumer->releaseBuffer(mFdp.ConsumeIntegral<int32_t>(), mFdp.ConsumeIntegral<uint64_t>(), |
| EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, releaseFence); |
| consumer->consumerDisconnect(); |
| } |
| |
| void BufferQueueFuzzer::invokeTypes() { |
| HStatus hStatus; |
| int32_t status = mFdp.PickValueInArray(kError); |
| bool bufferNeedsReallocation = mFdp.ConsumeBool(); |
| bool releaseAllBuffers = mFdp.ConsumeBool(); |
| b2h(status, &hStatus, &bufferNeedsReallocation, &releaseAllBuffers); |
| h2b(hStatus, &status); |
| |
| HConnectionType type; |
| int32_t apiConnection = mFdp.PickValueInArray(kAPIConnection); |
| b2h(apiConnection, &type); |
| h2b(type, &apiConnection); |
| } |
| |
| void BufferQueueFuzzer::invokeH2BGraphicBufferV1() { |
| sp<V1_0::utils::H2BGraphicBufferProducer> producer( |
| new V1_0::utils::H2BGraphicBufferProducer(new FakeGraphicBufferProducerV1())); |
| const sp<android::IProducerListener> listener; |
| android::IGraphicBufferProducer::QueueBufferOutput output; |
| uint32_t api = mFdp.ConsumeIntegral<uint32_t>(); |
| producer->connect(listener, api, mFdp.ConsumeBool() /*producerControlledByApp*/, &output); |
| |
| sp<GraphicBuffer> buffer; |
| int32_t slot = mFdp.ConsumeIntegral<int32_t>(); |
| producer->requestBuffer(slot, &buffer); |
| producer->setMaxDequeuedBufferCount(mFdp.ConsumeIntegral<int32_t>()); |
| producer->setAsyncMode(mFdp.ConsumeBool()); |
| |
| android::IGraphicBufferProducer::QueueBufferInput input; |
| input.fence = new Fence(memfd_create("ffd", MFD_ALLOW_SEALING)); |
| producer->attachBuffer(&slot, buffer); |
| producer->queueBuffer(slot, input, &output); |
| |
| int32_t format = mFdp.ConsumeIntegral<int32_t>(); |
| uint32_t width = mFdp.ConsumeIntegral<uint32_t>(); |
| uint32_t height = mFdp.ConsumeIntegral<uint32_t>(); |
| uint64_t usage = mFdp.ConsumeIntegral<uint64_t>(); |
| uint64_t outBufferAge; |
| FrameEventHistoryDelta outTimestamps; |
| sp<android::Fence> fence; |
| producer->dequeueBuffer(&slot, &fence, width, height, format, usage, &outBufferAge, |
| &outTimestamps); |
| producer->detachBuffer(slot); |
| producer->cancelBuffer(slot, fence); |
| |
| invokeQuery(producer); |
| |
| ManageResourceHandle handle(&mFdp); |
| producer->setSidebandStream(handle.getStream()); |
| |
| producer->allocateBuffers(width, height, format, usage); |
| producer->allowAllocation(mFdp.ConsumeBool() /*allow*/); |
| producer->setSharedBufferMode(mFdp.ConsumeBool() /*sharedBufferMode*/); |
| producer->setAutoRefresh(mFdp.ConsumeBool() /*autoRefresh*/); |
| |
| producer->setGenerationNumber(mFdp.ConsumeIntegral<uint32_t>()); |
| producer->setDequeueTimeout(mFdp.ConsumeIntegral<uint32_t>()); |
| producer->disconnect(api); |
| } |
| |
| void BufferQueueFuzzer::invokeH2BGraphicBufferV2() { |
| sp<V2_0::utils::H2BGraphicBufferProducer> producer( |
| new V2_0::utils::H2BGraphicBufferProducer(new FakeGraphicBufferProducerV2())); |
| const sp<android::IProducerListener> listener; |
| android::IGraphicBufferProducer::QueueBufferOutput output; |
| uint32_t api = mFdp.ConsumeIntegral<uint32_t>(); |
| producer->connect(listener, api, mFdp.ConsumeBool() /*producerControlledByApp*/, &output); |
| |
| sp<GraphicBuffer> buffer; |
| int32_t slot = mFdp.ConsumeIntegral<int32_t>(); |
| producer->requestBuffer(slot, &buffer); |
| producer->setMaxDequeuedBufferCount(mFdp.ConsumeIntegral<uint32_t>()); |
| producer->setAsyncMode(mFdp.ConsumeBool()); |
| |
| android::IGraphicBufferProducer::QueueBufferInput input; |
| input.fence = new Fence(memfd_create("ffd", MFD_ALLOW_SEALING)); |
| producer->attachBuffer(&slot, buffer); |
| producer->queueBuffer(slot, input, &output); |
| |
| int32_t format = mFdp.ConsumeIntegral<int32_t>(); |
| uint32_t width = mFdp.ConsumeIntegral<uint32_t>(); |
| uint32_t height = mFdp.ConsumeIntegral<uint32_t>(); |
| uint64_t usage = mFdp.ConsumeIntegral<uint64_t>(); |
| uint64_t outBufferAge; |
| FrameEventHistoryDelta outTimestamps; |
| sp<android::Fence> fence; |
| producer->dequeueBuffer(&slot, &fence, width, height, format, usage, &outBufferAge, |
| &outTimestamps); |
| producer->detachBuffer(slot); |
| producer->cancelBuffer(slot, fence); |
| |
| invokeQuery(producer); |
| |
| ManageResourceHandle handle(&mFdp); |
| producer->setSidebandStream(handle.getStream()); |
| |
| producer->allocateBuffers(width, height, format, usage); |
| producer->allowAllocation(mFdp.ConsumeBool() /*allow*/); |
| producer->setSharedBufferMode(mFdp.ConsumeBool() /*sharedBufferMode*/); |
| producer->setAutoRefresh(mFdp.ConsumeBool() /*autoRefresh*/); |
| |
| producer->setGenerationNumber(mFdp.ConsumeIntegral<uint32_t>()); |
| producer->setDequeueTimeout(mFdp.ConsumeIntegral<uint32_t>()); |
| producer->disconnect(api); |
| } |
| |
| void BufferQueueFuzzer::process() { |
| invokeBlastBufferQueue(); |
| invokeH2BGraphicBufferV1(); |
| invokeH2BGraphicBufferV2(); |
| invokeTypes(); |
| invokeBufferQueueConsumer(); |
| invokeBufferQueueProducer(); |
| } |
| |
| extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { |
| BufferQueueFuzzer bufferQueueFuzzer(data, size); |
| bufferQueueFuzzer.process(); |
| return 0; |
| } |