Merge changes I3f879fc3,Id828cef4,Ic7887d61 am: c93ffab0d3 am: 4ab211c4fd

Original change: https://android-review.googlesource.com/c/platform/frameworks/av/+/1519481

MUST ONLY BE SUBMITTED BY AUTOMERGER

Change-Id: Iacbff21b8e2513d2a2e87202111d011fc9d5b199
diff --git a/media/codec2/fuzzer/Android.bp b/media/codec2/fuzzer/Android.bp
new file mode 100644
index 0000000..2de400d
--- /dev/null
+++ b/media/codec2/fuzzer/Android.bp
@@ -0,0 +1,333 @@
+/*
+ * Copyright (C) 2020 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.
+ *
+ * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore
+ */
+
+cc_defaults {
+    name: "C2Fuzzer-defaults",
+
+    srcs: [
+        "C2Fuzzer.cpp",
+    ],
+
+    static_libs: [
+        "liblog",
+        "libion",
+        "libfmq",
+        "libbase",
+        "libutils",
+        "libcutils",
+        "libcodec2",
+        "libhidlbase",
+        "libdmabufheap",
+        "libcodec2_vndk",
+        "libnativewindow",
+        "libcodec2_soft_common",
+        "libsfplugin_ccodec_utils",
+        "libstagefright_foundation",
+        "libstagefright_bufferpool@2.0.1",
+        "android.hardware.graphics.mapper@2.0",
+        "android.hardware.graphics.mapper@3.0",
+        "android.hardware.media.bufferpool@2.0",
+        "android.hardware.graphics.allocator@2.0",
+        "android.hardware.graphics.allocator@3.0",
+        "android.hardware.graphics.bufferqueue@2.0",
+    ],
+
+    shared_libs: [
+        "libui",
+        "libdl",
+        "libbinder",
+        "libhardware",
+        "libvndksupport",
+        "libprocessgroup",
+    ],
+
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
+}
+
+cc_fuzz {
+    name: "C2FuzzerAvcDec",
+    defaults: ["C2Fuzzer-defaults"],
+
+    cflags: [
+        "-DC2COMPONENTNAME=\"c2.android.avc.decoder\"",
+    ],
+
+    static_libs: [
+        "libavcdec",
+        "libcodec2_soft_avcdec",
+    ],
+}
+
+cc_fuzz {
+    name: "C2FuzzerHevcDec",
+    defaults: ["C2Fuzzer-defaults"],
+
+    cflags: [
+        "-DC2COMPONENTNAME=\"c2.android.hevc.decoder\"",
+    ],
+
+    static_libs: [
+        "libhevcdec",
+        "libcodec2_soft_hevcdec",
+    ],
+}
+
+cc_fuzz {
+    name: "C2FuzzerMpeg2Dec",
+    defaults: ["C2Fuzzer-defaults"],
+
+    cflags: [
+        "-DC2COMPONENTNAME=\"c2.android.mpeg2.decoder\"",
+    ],
+
+    static_libs: [
+        "libmpeg2dec",
+        "libcodec2_soft_mpeg2dec",
+    ],
+}
+
+cc_fuzz {
+    name: "C2FuzzerMpeg4Dec",
+    defaults: ["C2Fuzzer-defaults"],
+
+    cflags: [
+        "-DC2COMPONENTNAME=\"c2.android.mpeg4.decoder\"",
+    ],
+
+    static_libs: [
+        "libstagefright_m4vh263dec",
+        "libcodec2_soft_mpeg4dec",
+    ],
+}
+
+cc_fuzz {
+    name: "C2FuzzerH263Dec",
+    defaults: ["C2Fuzzer-defaults"],
+
+    cflags: [
+        "-DC2COMPONENTNAME=\"c2.android.h263.decoder\"",
+    ],
+
+    static_libs: [
+        "libstagefright_m4vh263dec",
+        "libcodec2_soft_h263dec",
+    ],
+}
+
+cc_fuzz {
+    name: "C2FuzzerVp8Dec",
+    defaults: ["C2Fuzzer-defaults"],
+
+    cflags: [
+        "-DC2COMPONENTNAME=\"c2.android.vp8.decoder\"",
+    ],
+
+    static_libs: [
+        "libvpx",
+        "libcodec2_soft_vp8dec",
+    ],
+}
+
+cc_fuzz {
+    name: "C2FuzzerVp9Dec",
+    defaults: ["C2Fuzzer-defaults"],
+
+    cflags: [
+        "-DC2COMPONENTNAME=\"c2.android.vp9.decoder\"",
+    ],
+
+    static_libs: [
+        "libvpx",
+        "libcodec2_soft_vp9dec",
+    ],
+}
+
+cc_fuzz {
+    name: "C2FuzzerAacDec",
+    defaults: ["C2Fuzzer-defaults"],
+
+    cflags: [
+        "-DC2COMPONENTNAME=\"c2.android.aac.decoder\"",
+    ],
+
+    static_libs: [
+        "libFraunhoferAAC",
+        "libcodec2_soft_aacdec",
+    ],
+}
+
+cc_fuzz {
+    name: "C2FuzzerAmrnbDec",
+    defaults: ["C2Fuzzer-defaults"],
+
+    cflags: [
+        "-DC2COMPONENTNAME=\"c2.android.amrnb.decoder\"",
+    ],
+
+    static_libs: [
+        "libstagefright_amrnbdec",
+        "libstagefright_amrwbdec",
+        "libstagefright_amrnb_common",
+        "libcodec2_soft_amrnbdec",
+    ],
+}
+
+cc_fuzz {
+    name: "C2FuzzerAmrwbDec",
+    defaults: ["C2Fuzzer-defaults"],
+
+    cflags: [
+        "-DC2COMPONENTNAME=\"c2.android.amrwb.decoder\"",
+    ],
+
+    static_libs: [
+        "libstagefright_amrnbdec",
+        "libstagefright_amrwbdec",
+        "libstagefright_amrnb_common",
+        "libcodec2_soft_amrwbdec",
+    ],
+}
+
+cc_fuzz {
+    name: "C2FuzzerFlacDec",
+    defaults: ["C2Fuzzer-defaults"],
+
+    cflags: [
+        "-DC2COMPONENTNAME=\"c2.android.flac.decoder\"",
+    ],
+
+    static_libs: [
+        "libFLAC",
+        "libstagefright_flacdec",
+        "libcodec2_soft_flacdec",
+    ],
+}
+
+cc_fuzz {
+    name: "C2FuzzerG711AlawDec",
+    defaults: ["C2Fuzzer-defaults"],
+
+    cflags: [
+        "-DC2COMPONENTNAME=\"c2.android.g711.alaw.decoder\"",
+    ],
+
+    static_libs: [
+        "codecs_g711dec",
+        "libcodec2_soft_g711alawdec",
+    ],
+}
+
+cc_fuzz {
+    name: "C2FuzzerG711MlawDec",
+    defaults: ["C2Fuzzer-defaults"],
+
+    cflags: [
+        "-DC2COMPONENTNAME=\"c2.android.g711.mlaw.decoder\"",
+    ],
+
+    static_libs: [
+        "codecs_g711dec",
+        "libcodec2_soft_g711mlawdec",
+    ],
+}
+
+cc_fuzz {
+    name: "C2FuzzerGsmDec",
+    defaults: ["C2Fuzzer-defaults"],
+
+    cflags: [
+        "-DC2COMPONENTNAME=\"c2.android.gsm.decoder\"",
+    ],
+
+    static_libs: [
+        "libgsm",
+        "libcodec2_soft_gsmdec",
+    ],
+}
+
+cc_fuzz {
+    name: "C2FuzzerMp3Dec",
+    defaults: ["C2Fuzzer-defaults"],
+
+    cflags: [
+        "-DC2COMPONENTNAME=\"c2.android.mp3.decoder\"",
+    ],
+
+    static_libs: [
+        "libstagefright_mp3dec",
+        "libcodec2_soft_mp3dec",
+    ],
+}
+
+cc_fuzz {
+    name: "C2FuzzerOpusDec",
+    defaults: ["C2Fuzzer-defaults"],
+
+    cflags: [
+        "-DC2COMPONENTNAME=\"c2.android.opus.decoder\"",
+    ],
+
+    static_libs: [
+        "libopus",
+        "libcodec2_soft_opusdec",
+    ],
+}
+
+cc_fuzz {
+    name: "C2FuzzerRawDec",
+    defaults: ["C2Fuzzer-defaults"],
+
+    cflags: [
+        "-DC2COMPONENTNAME=\"c2.android.raw.decoder\"",
+    ],
+
+    static_libs: [
+        "libcodec2_soft_rawdec",
+    ],
+}
+
+cc_fuzz {
+    name: "C2FuzzerVorbisDec",
+    defaults: ["C2Fuzzer-defaults"],
+
+    cflags: [
+        "-DC2COMPONENTNAME=\"c2.android.vorbis.decoder\"",
+    ],
+
+    static_libs: [
+        "libvorbisidec",
+        "libcodec2_soft_vorbisdec",
+    ],
+}
+
+cc_fuzz {
+    name: "C2FuzzerXaacDec",
+    defaults: ["C2Fuzzer-defaults"],
+
+    cflags: [
+        "-DC2COMPONENTNAME=\"c2.android.xaac.decoder\"",
+    ],
+
+    static_libs: [
+        "libxaacdec",
+        "libcodec2_soft_xaacdec",
+    ],
+}
diff --git a/media/codec2/fuzzer/C2Fuzzer.cpp b/media/codec2/fuzzer/C2Fuzzer.cpp
new file mode 100644
index 0000000..71956a2
--- /dev/null
+++ b/media/codec2/fuzzer/C2Fuzzer.cpp
@@ -0,0 +1,318 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2020 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.
+ *
+ *****************************************************************************
+ * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore
+ */
+#include <stdio.h>
+
+#include <C2Fuzzer.h>
+
+using namespace android;
+
+class LinearBuffer : public C2Buffer {
+ public:
+  explicit LinearBuffer(const std::shared_ptr<C2LinearBlock>& block)
+      : C2Buffer({block->share(block->offset(), block->size(), ::C2Fence())}) {}
+
+  explicit LinearBuffer(const std::shared_ptr<C2LinearBlock>& block, size_t size)
+      : C2Buffer({block->share(block->offset(), size, ::C2Fence())}) {}
+};
+
+/**
+ * Handle Callback functions onWorkDone_nb(), onTripped_nb(), onError_nb() for C2 Components
+ */
+struct CodecListener : public C2Component::Listener {
+ public:
+  CodecListener(const std::function<void(std::weak_ptr<C2Component> comp,
+                                         std::list<std::unique_ptr<C2Work>>& workItems)>
+                    fn = nullptr)
+      : callBack(fn) {}
+  virtual void onWorkDone_nb(const std::weak_ptr<C2Component> comp,
+                             std::list<std::unique_ptr<C2Work>> workItems) {
+    if (callBack) {
+      callBack(comp, workItems);
+    }
+  }
+
+  virtual void onTripped_nb(const std::weak_ptr<C2Component> comp,
+                            const std::vector<std::shared_ptr<C2SettingResult>> settingResults) {
+    (void)comp;
+    (void)settingResults;
+  }
+
+  virtual void onError_nb(const std::weak_ptr<C2Component> comp, uint32_t errorCode) {
+    (void)comp;
+    (void)errorCode;
+  }
+
+  std::function<void(std::weak_ptr<C2Component> comp,
+                     std::list<std::unique_ptr<C2Work>>& workItems)> callBack;
+};
+
+/**
+ * Buffer source implementations to identify a frame and its size
+ */
+bool Codec2Fuzzer::BufferSource::searchForMarker() {
+  while (true) {
+    if (isMarker()) {
+      return true;
+    }
+    --mReadIndex;
+    if (mReadIndex > mSize) {
+      break;
+    }
+  }
+  return false;
+}
+
+void Codec2Fuzzer::BufferSource::parse() {
+  bool isFrameAvailable = true;
+  size_t bytesRemaining = mSize;
+  while (isFrameAvailable) {
+    isFrameAvailable = searchForMarker();
+    if (isFrameAvailable) {
+      size_t location = mReadIndex + kMarkerSize;
+      bool isCSD = isCSDMarker(location);
+      location += kMarkerSuffixSize;
+      uint8_t* framePtr = const_cast<uint8_t*>(&mData[location]);
+      size_t frameSize = bytesRemaining - location;
+      uint32_t flags = 0;
+      if (mFrameList.empty()) {
+        flags |= C2FrameData::FLAG_END_OF_STREAM;
+      } else if (isCSD) {
+        flags |= C2FrameData::FLAG_CODEC_CONFIG;
+      }
+      mFrameList.emplace_back(std::make_tuple(framePtr, frameSize, flags));
+      bytesRemaining -= (frameSize + kMarkerSize + kMarkerSuffixSize);
+      --mReadIndex;
+    }
+  }
+  if (mFrameList.empty()) {
+    /**
+     * Scenario where input data does not contain the custom frame markers.
+     * Hence feed the entire data as single frame.
+     */
+    mFrameList.emplace_back(
+        std::make_tuple(const_cast<uint8_t*>(mData), 0, C2FrameData::FLAG_END_OF_STREAM));
+    mFrameList.emplace_back(
+        std::make_tuple(const_cast<uint8_t*>(mData), mSize, C2FrameData::FLAG_CODEC_CONFIG));
+  }
+}
+
+FrameData Codec2Fuzzer::BufferSource::getFrame() {
+  FrameData frame = mFrameList.back();
+  mFrameList.pop_back();
+  return frame;
+}
+
+void Codec2Fuzzer::handleWorkDone(std::weak_ptr<C2Component> comp,
+                                  std::list<std::unique_ptr<C2Work>>& workItems) {
+  (void)comp;
+  for (std::unique_ptr<C2Work>& work : workItems) {
+    if (!work->worklets.empty()) {
+      if (work->worklets.front()->output.flags != C2FrameData::FLAG_INCOMPLETE) {
+        mEos = (work->worklets.front()->output.flags & C2FrameData::FLAG_END_OF_STREAM) != 0;
+        work->input.buffers.clear();
+        work->worklets.clear();
+        {
+          std::unique_lock<std::mutex> lock(mQueueLock);
+          mWorkQueue.push_back(std::move(work));
+          mQueueCondition.notify_all();
+        }
+        if (mEos) {
+          {
+            std::lock_guard<std::mutex> waitForDecodeComplete(mDecodeCompleteMutex);
+          }
+          mConditionalVariable.notify_one();
+        }
+      }
+    }
+  }
+}
+
+bool Codec2Fuzzer::initDecoder() {
+  std::vector<std::tuple<C2String, C2ComponentFactory::CreateCodec2FactoryFunc,
+        C2ComponentFactory::DestroyCodec2FactoryFunc>> codec2FactoryFunc;
+
+  codec2FactoryFunc.emplace_back(std::make_tuple(C2COMPONENTNAME,
+                                                &CreateCodec2Factory,
+                                                &DestroyCodec2Factory));
+
+  std::shared_ptr<C2ComponentStore> componentStore = GetTestComponentStore(codec2FactoryFunc);
+  if (!componentStore) {
+    return false;
+  }
+
+  std::shared_ptr<C2AllocatorStore> allocatorStore = GetCodec2PlatformAllocatorStore();
+  if (!allocatorStore) {
+    return false;
+  }
+
+  c2_status_t status =
+      allocatorStore->fetchAllocator(C2AllocatorStore::DEFAULT_LINEAR, &mLinearAllocator);
+  if (status != C2_OK) {
+    return false;
+  }
+
+  mLinearPool = std::make_shared<C2PooledBlockPool>(mLinearAllocator, ++mBlockPoolId);
+  if (!mLinearPool) {
+    return false;
+  }
+
+  for (int32_t i = 0; i < kNumberOfC2WorkItems; ++i) {
+    mWorkQueue.emplace_back(new C2Work);
+  }
+
+  status = componentStore->createComponent(C2COMPONENTNAME, &mComponent);
+  if (status != C2_OK) {
+    return false;
+  }
+
+  status = componentStore->createInterface(C2COMPONENTNAME, &mInterface);
+  if (status != C2_OK) {
+    return false;
+  }
+
+  C2ComponentKindSetting kind;
+  C2ComponentDomainSetting domain;
+  status = mInterface->query_vb({&kind, &domain}, {}, C2_MAY_BLOCK, nullptr);
+  if (status != C2_OK) {
+    return false;
+  }
+
+  std::vector<C2Param*> configParams;
+  if (domain.value == DOMAIN_VIDEO) {
+    C2StreamPictureSizeInfo::input inputSize(0u, kWidthOfVideo, kHeightOfVideo);
+    configParams.push_back(&inputSize);
+  } else if (domain.value == DOMAIN_AUDIO) {
+    C2StreamSampleRateInfo::output sampleRateInfo(0u, kSamplingRateOfAudio);
+    C2StreamChannelCountInfo::output channelCountInfo(0u, kChannelsOfAudio);
+    configParams.push_back(&sampleRateInfo);
+    configParams.push_back(&channelCountInfo);
+  }
+
+  mListener.reset(new CodecListener(
+      [this](std::weak_ptr<C2Component> comp, std::list<std::unique_ptr<C2Work>>& workItems) {
+        handleWorkDone(comp, workItems);
+      }));
+  if (!mListener) {
+    return false;
+  }
+
+  status = mComponent->setListener_vb(mListener, C2_DONT_BLOCK);
+  if (status != C2_OK) {
+    return false;
+  }
+
+  std::vector<std::unique_ptr<C2SettingResult>> failures;
+  componentStore->config_sm(configParams, &failures);
+  if (failures.size() != 0) {
+    return false;
+  }
+
+  status = mComponent->start();
+  if (status != C2_OK) {
+    return false;
+  }
+
+  return true;
+}
+
+void Codec2Fuzzer::deInitDecoder() {
+  mComponent->stop();
+  mComponent->reset();
+  mComponent->release();
+  mComponent = nullptr;
+}
+
+void Codec2Fuzzer::decodeFrames(const uint8_t* data, size_t size) {
+  mBufferSource = new BufferSource(data, size);
+  if (!mBufferSource) {
+    return;
+  }
+  mBufferSource->parse();
+  c2_status_t status = C2_OK;
+  size_t numFrames = 0;
+  while (!mBufferSource->isEos()) {
+    uint8_t* frame = nullptr;
+    size_t frameSize = 0;
+    FrameData frameData = mBufferSource->getFrame();
+    frame = std::get<0>(frameData);
+    frameSize = std::get<1>(frameData);
+
+    std::unique_ptr<C2Work> work;
+    {
+      std::unique_lock<std::mutex> lock(mQueueLock);
+      if (mWorkQueue.empty()) mQueueCondition.wait_for(lock, kC2FuzzerTimeOut);
+      if (!mWorkQueue.empty()) {
+        work.swap(mWorkQueue.front());
+        mWorkQueue.pop_front();
+      } else {
+        return;
+      }
+    }
+
+    work->input.flags = (C2FrameData::flags_t)std::get<2>(frameData);
+    work->input.ordinal.timestamp = 0;
+    work->input.ordinal.frameIndex = ++numFrames;
+    work->input.buffers.clear();
+    int32_t alignedSize = C2FUZZER_ALIGN(frameSize, PAGE_SIZE);
+
+    std::shared_ptr<C2LinearBlock> block;
+    status = mLinearPool->fetchLinearBlock(
+        alignedSize, {C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE}, &block);
+    if (status != C2_OK || block == nullptr) {
+      return;
+    }
+
+    C2WriteView view = block->map().get();
+    if (view.error() != C2_OK) {
+      return;
+    }
+    memcpy(view.base(), frame, frameSize);
+    work->input.buffers.emplace_back(new LinearBuffer(block, frameSize));
+    work->worklets.clear();
+    work->worklets.emplace_back(new C2Worklet);
+
+    std::list<std::unique_ptr<C2Work>> items;
+    items.push_back(std::move(work));
+    status = mComponent->queue_nb(&items);
+    if (status != C2_OK) {
+      return;
+    }
+  }
+  std::unique_lock<std::mutex> waitForDecodeComplete(mDecodeCompleteMutex);
+  mConditionalVariable.wait_for(waitForDecodeComplete, kC2FuzzerTimeOut, [this] { return mEos; });
+  std::list<std::unique_ptr<C2Work>> c2flushedWorks;
+  mComponent->flush_sm(C2Component::FLUSH_COMPONENT, &c2flushedWorks);
+  delete mBufferSource;
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+  if (size < 1) {
+    return 0;
+  }
+  Codec2Fuzzer* codec = new Codec2Fuzzer();
+  if (!codec) {
+    return 0;
+  }
+  if (codec->initDecoder()) {
+    codec->decodeFrames(data, size);
+  }
+  delete codec;
+  return 0;
+}
diff --git a/media/codec2/fuzzer/C2Fuzzer.h b/media/codec2/fuzzer/C2Fuzzer.h
new file mode 100644
index 0000000..2efad50
--- /dev/null
+++ b/media/codec2/fuzzer/C2Fuzzer.h
@@ -0,0 +1,114 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2020 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.
+ *
+ *****************************************************************************
+ * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore
+ */
+#ifndef __C2FUZZER_H__
+#define __C2FUZZER_H__
+
+#include <C2AllocatorIon.h>
+#include <C2Buffer.h>
+#include <C2BufferPriv.h>
+#include <C2Component.h>
+#include <C2Config.h>
+#include <C2PlatformSupport.h>
+
+using namespace std::chrono_literals;
+
+extern "C" ::C2ComponentFactory* CreateCodec2Factory();
+extern "C" void DestroyCodec2Factory(::C2ComponentFactory* factory);
+
+namespace android {
+
+#define C2FUZZER_ALIGN(_sz, _align) (((_sz) + ((_align)-1)) & ~((_align)-1))
+
+constexpr std::chrono::milliseconds kC2FuzzerTimeOut = 5000ms;
+constexpr int32_t kNumberOfC2WorkItems = 8;
+constexpr uint32_t kWidthOfVideo = 3840;
+constexpr uint32_t kHeightOfVideo = 2160;
+constexpr uint32_t kSamplingRateOfAudio = 48000;
+constexpr uint32_t kChannelsOfAudio = 8;
+
+typedef std::tuple<uint8_t*, size_t, uint32_t> FrameData;
+
+class Codec2Fuzzer {
+ public:
+  Codec2Fuzzer() = default;
+  ~Codec2Fuzzer() { deInitDecoder(); }
+  bool initDecoder();
+  void deInitDecoder();
+  void decodeFrames(const uint8_t* data, size_t size);
+
+  void handleWorkDone(std::weak_ptr<C2Component> comp,
+                      std::list<std::unique_ptr<C2Work>>& workItems);
+
+ private:
+  class BufferSource {
+   public:
+    BufferSource(const uint8_t* data, size_t size)
+        : mData(data), mSize(size), mReadIndex(size - kMarkerSize) {}
+    ~BufferSource() {
+      mData = nullptr;
+      mSize = 0;
+      mReadIndex = 0;
+      mFrameList.clear();
+    }
+    bool isEos() { return mFrameList.empty(); }
+    void parse();
+    FrameData getFrame();
+
+   private:
+    bool isMarker() { return (memcmp(&mData[mReadIndex], kMarker, kMarkerSize) == 0); }
+
+    bool isCSDMarker(size_t position) {
+      return (memcmp(&mData[position], kCsdMarkerSuffix, kMarkerSuffixSize) == 0);
+    }
+
+    bool searchForMarker();
+
+    const uint8_t* mData = nullptr;
+    size_t mSize = 0;
+    size_t mReadIndex = 0;
+    std::vector<FrameData> mFrameList;
+    static constexpr uint8_t kMarker[] = "_MARK";
+    static constexpr uint8_t kCsdMarkerSuffix[] = "_H_";
+    static constexpr uint8_t kFrameMarkerSuffix[] = "_F_";
+    // All markers should be 5 bytes long ( sizeof '_MARK' which is 5)
+    static constexpr size_t kMarkerSize = (sizeof(kMarker) - 1);
+    // All marker types should be 3 bytes long ('_H_', '_F_')
+    static constexpr size_t kMarkerSuffixSize = 3;
+  };
+
+  BufferSource* mBufferSource;
+  bool mEos = false;
+  C2BlockPool::local_id_t mBlockPoolId;
+
+  std::shared_ptr<C2BlockPool> mLinearPool;
+  std::shared_ptr<C2Allocator> mLinearAllocator;
+  std::shared_ptr<C2Component::Listener> mListener;
+  std::shared_ptr<C2Component> mComponent;
+  std::shared_ptr<C2ComponentInterface> mInterface;
+  std::mutex mQueueLock;
+  std::condition_variable mQueueCondition;
+  std::list<std::unique_ptr<C2Work>> mWorkQueue;
+  std::mutex mDecodeCompleteMutex;
+  std::condition_variable mConditionalVariable;
+};
+
+}  // namespace android
+
+#endif  // __C2FUZZER_H__
diff --git a/media/codec2/vndk/C2Store.cpp b/media/codec2/vndk/C2Store.cpp
index 1e907c1..499ab72 100644
--- a/media/codec2/vndk/C2Store.cpp
+++ b/media/codec2/vndk/C2Store.cpp
@@ -622,6 +622,12 @@
             std::vector<std::unique_ptr<C2SettingResult>> *const failures) override;
     C2PlatformComponentStore();
 
+    // For testing only
+    C2PlatformComponentStore(
+            std::vector<std::tuple<C2String,
+                                   C2ComponentFactory::CreateCodec2FactoryFunc,
+                                   C2ComponentFactory::DestroyCodec2FactoryFunc>>);
+
     virtual ~C2PlatformComponentStore() override = default;
 
 private:
@@ -662,6 +668,24 @@
         }
 
         /**
+         * Creates an uninitialized component module.
+         * NOTE: For testing only
+         *
+         * \param name[in]  component name.
+         *
+         * \note Only used by ComponentLoader.
+         */
+        ComponentModule(
+                C2ComponentFactory::CreateCodec2FactoryFunc createFactory,
+                C2ComponentFactory::DestroyCodec2FactoryFunc destroyFactory)
+            : mInit(C2_NO_INIT),
+              mLibHandle(nullptr),
+              createFactory(createFactory),
+              destroyFactory(destroyFactory),
+              mComponentFactory(nullptr) {
+        }
+
+        /**
          * Initializes a component module with a given library path. Must be called exactly once.
          *
          * \note Only used by ComponentLoader.
@@ -717,7 +741,13 @@
             std::lock_guard<std::mutex> lock(mMutex);
             std::shared_ptr<ComponentModule> localModule = mModule.lock();
             if (localModule == nullptr) {
-                localModule = std::make_shared<ComponentModule>();
+                if(mCreateFactory) {
+                    // For testing only
+                    localModule = std::make_shared<ComponentModule>(mCreateFactory,
+                                                                    mDestroyFactory);
+                } else {
+                    localModule = std::make_shared<ComponentModule>();
+                }
                 res = localModule->init(mLibPath);
                 if (res == C2_OK) {
                     mModule = localModule;
@@ -733,10 +763,22 @@
         ComponentLoader(std::string libPath)
             : mLibPath(libPath) {}
 
+        // For testing only
+        ComponentLoader(std::tuple<C2String,
+                          C2ComponentFactory::CreateCodec2FactoryFunc,
+                          C2ComponentFactory::DestroyCodec2FactoryFunc> func)
+            : mLibPath(std::get<0>(func)),
+              mCreateFactory(std::get<1>(func)),
+              mDestroyFactory(std::get<2>(func)) {}
+
     private:
         std::mutex mMutex; ///< mutex guarding the module
         std::weak_ptr<ComponentModule> mModule; ///< weak reference to the loaded module
         std::string mLibPath; ///< library path
+
+        // For testing only
+        C2ComponentFactory::CreateCodec2FactoryFunc mCreateFactory = nullptr;
+        C2ComponentFactory::DestroyCodec2FactoryFunc mDestroyFactory = nullptr;
     };
 
     struct Interface : public C2InterfaceHelper {
@@ -846,25 +888,33 @@
 
     std::shared_ptr<C2ReflectorHelper> mReflector;
     Interface mInterface;
+
+    // For testing only
+    std::vector<std::tuple<C2String,
+                          C2ComponentFactory::CreateCodec2FactoryFunc,
+                          C2ComponentFactory::DestroyCodec2FactoryFunc>> mCodec2FactoryFuncs;
 };
 
 c2_status_t C2PlatformComponentStore::ComponentModule::init(
         std::string libPath) {
     ALOGV("in %s", __func__);
     ALOGV("loading dll");
-    mLibHandle = dlopen(libPath.c_str(), RTLD_NOW|RTLD_NODELETE);
-    LOG_ALWAYS_FATAL_IF(mLibHandle == nullptr,
-            "could not dlopen %s: %s", libPath.c_str(), dlerror());
 
-    createFactory =
-        (C2ComponentFactory::CreateCodec2FactoryFunc)dlsym(mLibHandle, "CreateCodec2Factory");
-    LOG_ALWAYS_FATAL_IF(createFactory == nullptr,
-            "createFactory is null in %s", libPath.c_str());
+    if(!createFactory) {
+        mLibHandle = dlopen(libPath.c_str(), RTLD_NOW|RTLD_NODELETE);
+        LOG_ALWAYS_FATAL_IF(mLibHandle == nullptr,
+                "could not dlopen %s: %s", libPath.c_str(), dlerror());
 
-    destroyFactory =
-        (C2ComponentFactory::DestroyCodec2FactoryFunc)dlsym(mLibHandle, "DestroyCodec2Factory");
-    LOG_ALWAYS_FATAL_IF(destroyFactory == nullptr,
-            "destroyFactory is null in %s", libPath.c_str());
+        createFactory =
+            (C2ComponentFactory::CreateCodec2FactoryFunc)dlsym(mLibHandle, "CreateCodec2Factory");
+        LOG_ALWAYS_FATAL_IF(createFactory == nullptr,
+                "createFactory is null in %s", libPath.c_str());
+
+        destroyFactory =
+            (C2ComponentFactory::DestroyCodec2FactoryFunc)dlsym(mLibHandle, "DestroyCodec2Factory");
+        LOG_ALWAYS_FATAL_IF(destroyFactory == nullptr,
+                "destroyFactory is null in %s", libPath.c_str());
+    }
 
     mComponentFactory = createFactory();
     if (mComponentFactory == nullptr) {
@@ -1065,6 +1115,22 @@
     emplace("libcodec2_soft_vp8enc.so");
     emplace("libcodec2_soft_vp9dec.so");
     emplace("libcodec2_soft_vp9enc.so");
+
+}
+
+// For testing only
+C2PlatformComponentStore::C2PlatformComponentStore(
+    std::vector<std::tuple<C2String,
+                C2ComponentFactory::CreateCodec2FactoryFunc,
+                C2ComponentFactory::DestroyCodec2FactoryFunc>> funcs)
+    : mVisited(false),
+      mReflector(std::make_shared<C2ReflectorHelper>()),
+      mInterface(mReflector),
+      mCodec2FactoryFuncs(funcs) {
+
+    for(auto const& func: mCodec2FactoryFuncs) {
+        mComponents.emplace(std::get<0>(func), func);
+    }
 }
 
 c2_status_t C2PlatformComponentStore::copyBuffer(
@@ -1184,4 +1250,11 @@
     return store;
 }
 
+// For testing only
+std::shared_ptr<C2ComponentStore> GetTestComponentStore(
+        std::vector<std::tuple<C2String,
+        C2ComponentFactory::CreateCodec2FactoryFunc,
+        C2ComponentFactory::DestroyCodec2FactoryFunc>> funcs) {
+    return std::shared_ptr<C2ComponentStore>(new C2PlatformComponentStore(funcs));
+}
 } // namespace android
diff --git a/media/codec2/vndk/include/C2PlatformSupport.h b/media/codec2/vndk/include/C2PlatformSupport.h
index 4814494..6d351c2 100644
--- a/media/codec2/vndk/include/C2PlatformSupport.h
+++ b/media/codec2/vndk/include/C2PlatformSupport.h
@@ -144,6 +144,15 @@
 std::shared_ptr<C2ComponentStore> GetCodec2PlatformComponentStore();
 
 /**
+ * Returns the platform component store.
+ * NOTE: For testing only
+ * \retval nullptr if the platform component store could not be obtained
+ */
+std::shared_ptr<C2ComponentStore> GetTestComponentStore(
+        std::vector<std::tuple<C2String, C2ComponentFactory::CreateCodec2FactoryFunc,
+        C2ComponentFactory::DestroyCodec2FactoryFunc>>);
+
+/**
  * Sets the preferred component store in this process for the sole purpose of accessing its
  * interface. If this is not called, the default IComponentStore HAL (if exists) is the preferred
  * store for this purpose. If the default IComponentStore HAL is not present, the platform