Merge "AmrnbEncoderTest: Added AndroidTest.xml to run test with atest"
diff --git a/media/codec2/sfplugin/CCodec.cpp b/media/codec2/sfplugin/CCodec.cpp
index 4a31953..65d7a39 100644
--- a/media/codec2/sfplugin/CCodec.cpp
+++ b/media/codec2/sfplugin/CCodec.cpp
@@ -1295,6 +1295,8 @@
         mCallback->onError(err2, ACTION_CODE_FATAL);
         return;
     }
+    // We're not starting after flush.
+    (void)mSentConfigAfterResume.test_and_set();
     err2 = mChannel->start(inputFormat, outputFormat);
     if (err2 != OK) {
         mCallback->onError(err2, ACTION_CODE_FATAL);
@@ -1523,18 +1525,26 @@
 }
 
 void CCodec::signalResume() {
-    auto setResuming = [this] {
+    std::shared_ptr<Codec2Client::Component> comp;
+    auto setResuming = [this, &comp] {
         Mutexed<State>::Locked state(mState);
         if (state->get() != FLUSHED) {
             return UNKNOWN_ERROR;
         }
         state->set(RESUMING);
+        comp = state->comp;
         return OK;
     };
     if (tryAndReportOnError(setResuming) != OK) {
         return;
     }
 
+    mSentConfigAfterResume.clear();
+    {
+        Mutexed<Config>::Locked config(mConfig);
+        config->queryConfiguration(comp);
+    }
+
     (void)mChannel->start(nullptr, nullptr);
 
     {
@@ -1730,7 +1740,7 @@
 
             // handle configuration changes in work done
             Mutexed<Config>::Locked config(mConfig);
-            bool changed = false;
+            bool changed = !mSentConfigAfterResume.test_and_set();
             Config::Watcher<C2StreamInitDataInfo::output> initData =
                 config->watch<C2StreamInitDataInfo::output>();
             if (!work->worklets.empty()
@@ -1762,7 +1772,9 @@
                     ++stream;
                 }
 
-                changed = config->updateConfiguration(updates, config->mOutputDomain);
+                if (config->updateConfiguration(updates, config->mOutputDomain)) {
+                    changed = true;
+                }
 
                 // copy standard infos to graphic buffers if not already present (otherwise, we
                 // may overwrite the actual intermediate value with a final value)
diff --git a/media/codec2/sfplugin/CCodec.h b/media/codec2/sfplugin/CCodec.h
index b0b3c4f..a580d1d 100644
--- a/media/codec2/sfplugin/CCodec.h
+++ b/media/codec2/sfplugin/CCodec.h
@@ -17,6 +17,7 @@
 #ifndef C_CODEC_H_
 #define C_CODEC_H_
 
+#include <atomic>
 #include <chrono>
 #include <list>
 #include <memory>
@@ -175,6 +176,7 @@
     typedef CCodecConfig Config;
     Mutexed<Config> mConfig;
     Mutexed<std::list<std::unique_ptr<C2Work>>> mWorkDoneQueue;
+    std::atomic_flag mSentConfigAfterResume;
 
     friend class CCodecCallbackImpl;
 
diff --git a/media/codec2/sfplugin/CCodecBufferChannel.cpp b/media/codec2/sfplugin/CCodecBufferChannel.cpp
index 375ce17..5f969db 100644
--- a/media/codec2/sfplugin/CCodecBufferChannel.cpp
+++ b/media/codec2/sfplugin/CCodecBufferChannel.cpp
@@ -1277,6 +1277,24 @@
         std::unique_ptr<C2Work> work,
         const sp<AMessage> &outputFormat,
         const C2StreamInitDataInfo::output *initData) {
+    if (outputFormat != nullptr) {
+        Mutexed<Output>::Locked output(mOutput);
+        ALOGD("[%s] onWorkDone: output format changed to %s",
+                mName, outputFormat->debugString().c_str());
+        output->buffers->setFormat(outputFormat);
+
+        AString mediaType;
+        if (outputFormat->findString(KEY_MIME, &mediaType)
+                && mediaType == MIMETYPE_AUDIO_RAW) {
+            int32_t channelCount;
+            int32_t sampleRate;
+            if (outputFormat->findInt32(KEY_CHANNEL_COUNT, &channelCount)
+                    && outputFormat->findInt32(KEY_SAMPLE_RATE, &sampleRate)) {
+                output->buffers->updateSkipCutBuffer(sampleRate, channelCount);
+            }
+        }
+    }
+
     if ((work->input.ordinal.frameIndex - mFirstValidFrameIndex.load()).peek() < 0) {
         // Discard frames from previous generation.
         ALOGD("[%s] Discard frames from previous generation.", mName);
@@ -1454,24 +1472,6 @@
         }
     }
 
-    if (outputFormat != nullptr) {
-        Mutexed<Output>::Locked output(mOutput);
-        ALOGD("[%s] onWorkDone: output format changed to %s",
-                mName, outputFormat->debugString().c_str());
-        output->buffers->setFormat(outputFormat);
-
-        AString mediaType;
-        if (outputFormat->findString(KEY_MIME, &mediaType)
-                && mediaType == MIMETYPE_AUDIO_RAW) {
-            int32_t channelCount;
-            int32_t sampleRate;
-            if (outputFormat->findInt32(KEY_CHANNEL_COUNT, &channelCount)
-                    && outputFormat->findInt32(KEY_SAMPLE_RATE, &sampleRate)) {
-                output->buffers->updateSkipCutBuffer(sampleRate, channelCount);
-            }
-        }
-    }
-
     int32_t flags = 0;
     if (worklet->output.flags & C2FrameData::FLAG_END_OF_STREAM) {
         flags |= MediaCodec::BUFFER_FLAG_EOS;
diff --git a/media/libaudioprocessing/Android.bp b/media/libaudioprocessing/Android.bp
index 9b5d58c..e756ada 100644
--- a/media/libaudioprocessing/Android.bp
+++ b/media/libaudioprocessing/Android.bp
@@ -19,6 +19,25 @@
         // uncomment to disable NEON on architectures that actually do support NEON, for benchmarking
         // "-DUSE_NEON=false",
     ],
+
+    arch: {
+        x86: {
+            avx2: {
+                cflags: [
+                    "-mavx2",
+                    "-mfma",
+                ],
+            },
+        },
+        x86_64: {
+            avx2: {
+                cflags: [
+                    "-mavx2",
+                    "-mfma",
+                ],
+            },
+        },
+    },
 }
 
 cc_library_shared {
diff --git a/media/libaudioprocessing/AudioResamplerFirOps.h b/media/libaudioprocessing/AudioResamplerFirOps.h
index 2e4cee3..a3f5ff5 100644
--- a/media/libaudioprocessing/AudioResamplerFirOps.h
+++ b/media/libaudioprocessing/AudioResamplerFirOps.h
@@ -36,13 +36,20 @@
 #include <arm_neon.h>
 #endif
 
-#if defined(__SSSE3__)  // Should be supported in x86 ABI for both 32 & 64-bit.
+#if defined(__AVX2__)  // Should be supported in x86 ABI for both 32 & 64-bit.
+#define USE_AVX2 (true)  // Inference AVX2/FMA Intrinsics
 #define USE_SSE (true)
+#include <immintrin.h>
+#elif defined(__SSSE3__)  // Should be supported in x86 ABI for both 32 & 64-bit.
+#define USE_SSE (true)  // Inference SSE Intrinsics
+#define USE_AVX2 (false)
 #include <tmmintrin.h>
 #else
 #define USE_SSE (false)
+#define USE_AVX2(false)
 #endif
 
+
 template<typename T, typename U>
 struct is_same
 {
diff --git a/media/libaudioprocessing/AudioResamplerFirProcessSSE.h b/media/libaudioprocessing/AudioResamplerFirProcessSSE.h
index 30233b5..1c16bc4 100644
--- a/media/libaudioprocessing/AudioResamplerFirProcessSSE.h
+++ b/media/libaudioprocessing/AudioResamplerFirProcessSSE.h
@@ -80,11 +80,16 @@
             posCoef1 = _mm_sub_ps(posCoef1, posCoef);
             negCoef = _mm_sub_ps(negCoef, negCoef1);
 
+
+            #if USE_AVX2
+            posCoef = _mm_fmadd_ps(posCoef1, interp, posCoef);
+            negCoef = _mm_fmadd_ps(negCoef, interp, negCoef1);
+            #else
             posCoef1 = _mm_mul_ps(posCoef1, interp);
             negCoef = _mm_mul_ps(negCoef, interp);
-
             posCoef = _mm_add_ps(posCoef1, posCoef);
             negCoef = _mm_add_ps(negCoef, negCoef1);
+            #endif //USE_AVX2
         }
         switch (CHANNELS) {
         case 1: {
@@ -94,11 +99,17 @@
             sN += 4;
 
             posSamp = _mm_shuffle_ps(posSamp, posSamp, 0x1B);
+
+            #if USE_AVX2
+            accL = _mm_fmadd_ps(posSamp, posCoef, accL);
+            accL = _mm_fmadd_ps(negSamp, negCoef, accL);
+            #else
             posSamp = _mm_mul_ps(posSamp, posCoef);
             negSamp = _mm_mul_ps(negSamp, negCoef);
-
             accL = _mm_add_ps(accL, posSamp);
             accL = _mm_add_ps(accL, negSamp);
+            #endif
+
         } break;
         case 2: {
             __m128 posSamp0 = _mm_loadu_ps(sP);
@@ -114,15 +125,23 @@
             __m128 negSampL = _mm_shuffle_ps(negSamp0, negSamp1, 0x88);
             __m128 negSampR = _mm_shuffle_ps(negSamp0, negSamp1, 0xDD);
 
-            posSampL = _mm_mul_ps(posSampL, posCoef);
-            posSampR = _mm_mul_ps(posSampR, posCoef);
-            negSampL = _mm_mul_ps(negSampL, negCoef);
-            negSampR = _mm_mul_ps(negSampR, negCoef);
+           #if USE_AVX2
+           accL = _mm_fmadd_ps(posSampL, posCoef, accL);
+           accR = _mm_fmadd_ps(posSampR, posCoef, accR);
+           accL = _mm_fmadd_ps(negSampL, negCoef, accL);
+           accR = _mm_fmadd_ps(negSampR, negCoef, accR);
+           #else
+           posSampL = _mm_mul_ps(posSampL, posCoef);
+           posSampR = _mm_mul_ps(posSampR, posCoef);
+           negSampL = _mm_mul_ps(negSampL, negCoef);
+           negSampR = _mm_mul_ps(negSampR, negCoef);
 
-            accL = _mm_add_ps(accL, posSampL);
-            accR = _mm_add_ps(accR, posSampR);
-            accL = _mm_add_ps(accL, negSampL);
-            accR = _mm_add_ps(accR, negSampR);
+           accL = _mm_add_ps(accL, posSampL);
+           accR = _mm_add_ps(accR, posSampR);
+           accL = _mm_add_ps(accL, negSampL);
+           accR = _mm_add_ps(accR, negSampR);
+           #endif
+
         } break;
         }
     } while (count -= 4);
@@ -144,9 +163,13 @@
         outAccum = _mm_hadd_ps(accL, accR);
         outAccum = _mm_hadd_ps(outAccum, outAccum);
     }
-
+    #if USE_AVX2
+    outSamp = _mm_fmadd_ps(outAccum, vLR,outSamp);
+    #else
     outAccum = _mm_mul_ps(outAccum, vLR);
     outSamp = _mm_add_ps(outSamp, outAccum);
+    #endif
+
     _mm_storel_pi(reinterpret_cast<__m64*>(out), outSamp);
 }
 
diff --git a/media/libeffects/lvm/lib/Bass/src/LVDBE_Control.cpp b/media/libeffects/lvm/lib/Bass/src/LVDBE_Control.cpp
index cc9643d..53feae8 100644
--- a/media/libeffects/lvm/lib/Bass/src/LVDBE_Control.cpp
+++ b/media/libeffects/lvm/lib/Bass/src/LVDBE_Control.cpp
@@ -115,8 +115,7 @@
      * Setup the high pass filter
      */
     LoadConst_Float(0,                                          /* Clear the history, value 0 */
-                   (LVM_FLOAT *)&pInstance->pData->HPFTaps,     /* Destination Cast to void: \
-                                                                  no dereferencing in function*/
+                   (LVM_FLOAT *)&pInstance->pData->HPFTaps,     /* Destination */
                     sizeof(pInstance->pData->HPFTaps) / sizeof(LVM_FLOAT)); /* Number of words */
     BQ_2I_D32F32Cll_TRC_WRA_01_Init(&pInstance->pCoef->HPFInstance,    /* Initialise the filter */
                                     &pInstance->pData->HPFTaps,
@@ -126,8 +125,7 @@
      * Setup the band pass filter
      */
     LoadConst_Float(0,                                           /* Clear the history, value 0 */
-                 (LVM_FLOAT *)&pInstance->pData->BPFTaps,        /* Destination Cast to void: \
-                                                                    no dereferencing in function*/
+                 (LVM_FLOAT *)&pInstance->pData->BPFTaps,        /* Destination */
                  sizeof(pInstance->pData->BPFTaps) / sizeof(LVM_FLOAT));   /* Number of words */
     BP_1I_D32F32Cll_TRC_WRA_02_Init(&pInstance->pCoef->BPFInstance,    /* Initialise the filter */
                                     &pInstance->pData->BPFTaps,
diff --git a/media/libeffects/lvm/lib/Reverb/src/LVREV_ApplyNewSettings.cpp b/media/libeffects/lvm/lib/Reverb/src/LVREV_ApplyNewSettings.cpp
index 86a4ca2..1f0d39b 100644
--- a/media/libeffects/lvm/lib/Reverb/src/LVREV_ApplyNewSettings.cpp
+++ b/media/libeffects/lvm/lib/Reverb/src/LVREV_ApplyNewSettings.cpp
@@ -83,8 +83,7 @@
         FO_1I_D32F32Cll_TRC_WRA_01_Init( &pPrivate->pFastCoef->HPCoefs,
                                          &pPrivate->pFastData->HPTaps, &Coeffs);
         LoadConst_Float(0,
-                (LVM_FLOAT *)&pPrivate->pFastData->HPTaps, /* Destination Cast to void: \
-                                                                 no dereferencing in function*/
+                (LVM_FLOAT *)&pPrivate->pFastData->HPTaps,
                         sizeof(Biquad_1I_Order1_FLOAT_Taps_t) / sizeof(LVM_FLOAT));
     }
 
@@ -116,8 +115,7 @@
         FO_1I_D32F32Cll_TRC_WRA_01_Init( &pPrivate->pFastCoef->LPCoefs,
                                          &pPrivate->pFastData->LPTaps, &Coeffs);
         LoadConst_Float(0,
-                (LVM_FLOAT *)&pPrivate->pFastData->LPTaps, /* Destination Cast to void: \
-                                                                 no dereferencing in function*/
+                (LVM_FLOAT *)&pPrivate->pFastData->LPTaps,
                         sizeof(Biquad_1I_Order1_FLOAT_Taps_t) / sizeof(LVM_FLOAT));
     }
 
diff --git a/media/libeffects/lvm/lib/Reverb/src/LVREV_ClearAudioBuffers.cpp b/media/libeffects/lvm/lib/Reverb/src/LVREV_ClearAudioBuffers.cpp
index 8b38a16..586539f 100644
--- a/media/libeffects/lvm/lib/Reverb/src/LVREV_ClearAudioBuffers.cpp
+++ b/media/libeffects/lvm/lib/Reverb/src/LVREV_ClearAudioBuffers.cpp
@@ -60,12 +60,10 @@
      */
 
     LoadConst_Float(0,
-        (LVM_FLOAT *)&pLVREV_Private->pFastData->HPTaps, /* Destination Cast to void: \
-                                                         no dereferencing in function*/
+        (LVM_FLOAT *)&pLVREV_Private->pFastData->HPTaps,
         2);
     LoadConst_Float(0,
-        (LVM_FLOAT *)&pLVREV_Private->pFastData->LPTaps, /* Destination Cast to void: \
-                                                         no dereferencing in function*/
+        (LVM_FLOAT *)&pLVREV_Private->pFastData->LPTaps,
         2);
     if((LVM_UINT16)pLVREV_Private->InstanceParams.NumDelays == LVREV_DELAYLINES_4)
     {
diff --git a/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Equaliser.cpp b/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Equaliser.cpp
index ecf949d..431b7e3 100644
--- a/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Equaliser.cpp
+++ b/media/libeffects/lvm/lib/StereoWidening/src/LVCS_Equaliser.cpp
@@ -91,8 +91,7 @@
         Coeffs.B2 = (LVM_FLOAT)-pEqualiserCoefTable[Offset].B2;
 
         LoadConst_Float((LVM_INT16)0,                                         /* Value */
-                        (LVM_FLOAT *)&pData->EqualiserBiquadTaps, /* Destination Cast to void:\
-                                                                  no dereferencing in function*/
+                        (LVM_FLOAT *)&pData->EqualiserBiquadTaps, /* Destination */
                         /* Number of words */
                         (LVM_UINT16)(sizeof(pData->EqualiserBiquadTaps) / sizeof(LVM_FLOAT)));
 
diff --git a/media/libeffects/lvm/lib/StereoWidening/src/LVCS_ReverbGenerator.cpp b/media/libeffects/lvm/lib/StereoWidening/src/LVCS_ReverbGenerator.cpp
index 68a7120..d0e6e09 100644
--- a/media/libeffects/lvm/lib/StereoWidening/src/LVCS_ReverbGenerator.cpp
+++ b/media/libeffects/lvm/lib/StereoWidening/src/LVCS_ReverbGenerator.cpp
@@ -109,8 +109,7 @@
         Coeffs.B2 = (LVM_FLOAT)-pReverbCoefTable[Offset].B2;
 
         LoadConst_Float(0,                                 /* Value */
-                        (LVM_FLOAT *)&pData->ReverbBiquadTaps,  /* Destination Cast to void:
-                                                             no dereferencing in function*/
+                        (LVM_FLOAT *)&pData->ReverbBiquadTaps, /* Destination */
                         /* Number of words */
                         (LVM_UINT16)(sizeof(pData->ReverbBiquadTaps) / sizeof(LVM_FLOAT)));
 
diff --git a/media/libeffects/lvm/lib/StereoWidening/src/LVCS_StereoEnhancer.cpp b/media/libeffects/lvm/lib/StereoWidening/src/LVCS_StereoEnhancer.cpp
index 9cfc9a0..7fd8444 100644
--- a/media/libeffects/lvm/lib/StereoWidening/src/LVCS_StereoEnhancer.cpp
+++ b/media/libeffects/lvm/lib/StereoWidening/src/LVCS_StereoEnhancer.cpp
@@ -87,8 +87,7 @@
 
         /* Clear the taps */
         LoadConst_Float(0,                                  /* Value */
-                        (LVM_FLOAT *)&pData->SEBiquadTapsMid,    /* Destination Cast to void:\
-                                                              no dereferencing in function*/
+                        (LVM_FLOAT *)&pData->SEBiquadTapsMid,    /* Destination */
                         /* Number of words */
                         (LVM_UINT16)(sizeof(pData->SEBiquadTapsMid) / sizeof(LVM_FLOAT)));
 
@@ -115,8 +114,7 @@
 
         /* Clear the taps */
         LoadConst_Float(0,                                /* Value */
-                        (LVM_FLOAT *)&pData->SEBiquadTapsSide, /* Destination Cast to void:\
-                                                             no dereferencing in function*/
+                        (LVM_FLOAT *)&pData->SEBiquadTapsSide, /* Destination */
                         /* Number of words */
                         (LVM_UINT16)(sizeof(pData->SEBiquadTapsSide) / sizeof(LVM_FLOAT)));
         /* Callbacks */
diff --git a/media/libstagefright/MediaExtractorFactory.cpp b/media/libstagefright/MediaExtractorFactory.cpp
index 7689691..9e85475 100644
--- a/media/libstagefright/MediaExtractorFactory.cpp
+++ b/media/libstagefright/MediaExtractorFactory.cpp
@@ -276,7 +276,7 @@
 
     std::shared_ptr<std::list<sp<ExtractorPlugin>>> newList(new std::list<sp<ExtractorPlugin>>());
 
-    android_namespace_t *mediaNs = android_get_exported_namespace("com.android.media");
+    android_namespace_t *mediaNs = android_get_exported_namespace("com_android_media");
     if (mediaNs != NULL) {
         const android_dlextinfo dlextinfo = {
             .flags = ANDROID_DLEXT_USE_NAMESPACE,
diff --git a/media/libstagefright/codecs/amrwbenc/test/AndroidTest.xml b/media/libstagefright/codecs/amrwbenc/test/AndroidTest.xml
new file mode 100644
index 0000000..46f147c
--- /dev/null
+++ b/media/libstagefright/codecs/amrwbenc/test/AndroidTest.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<configuration description="Test module config for Amr-wb Encoder unit test">
+    <option name="test-suite-tag" value="AmrwbEncoderTest" />
+    <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+        <option name="cleanup" value="true" />
+        <option name="push" value="AmrwbEncoderTest->/data/local/tmp/AmrwbEncoderTest" />
+        <option name="push-file"
+            key="https://storage.googleapis.com/android_media/frameworks/av/media/libstagefright/codecs/amrwbenc/test/AmrwbEncoderTest.zip?unzip=true"
+            value="/data/local/tmp/AmrwbEncoderTestRes/" />
+    </target_preparer>
+
+    <test class="com.android.tradefed.testtype.GTest" >
+        <option name="native-test-device-path" value="/data/local/tmp" />
+        <option name="module-name" value="AmrwbEncoderTest" />
+        <option name="native-test-flag" value="-P /data/local/tmp/AmrwbEncoderTestRes/" />
+    </test>
+</configuration>
diff --git a/media/libstagefright/codecs/amrwbenc/test/README.md b/media/libstagefright/codecs/amrwbenc/test/README.md
index ea2135f..78762cb 100644
--- a/media/libstagefright/codecs/amrwbenc/test/README.md
+++ b/media/libstagefright/codecs/amrwbenc/test/README.md
@@ -22,13 +22,18 @@
 adb push ${OUT}/data/nativetest/AmrwbEncoderTest/AmrwbEncoderTest /data/local/tmp/
 ```
 
-The resource file for the tests is taken from [here](https://drive.google.com/drive/folders/13cM4tAaVFrmr-zGFqaAzFBbKs75pnm9b). Push these files into device for testing.
-Download amr-wb_encoder folder and push all the files in this folder to /data/local/tmp/ on the device.
+The resource file for the tests is taken from [here](https://storage.googleapis.com/android_media/frameworks/av/media/libstagefright/codecs/amrwbenc/test/AmrwbEncoderTest.zip). Download, unzip and push these files into device for testing.
+
 ```
-adb push amr-wb_encoder/. /data/local/tmp/
+adb push AmrwbEncoderTestRes/. /data/local/tmp/
 ```
 
 usage: AmrwbEncoderTest -P \<path_to_folder\>
 ```
-adb shell /data/local/tmp/AmrwbEncoderTest -P /data/local/tmp/
+adb shell /data/local/tmp/AmrwbEncoderTest -P /data/local/tmp/AmrwbEncoderTestRes/
+```
+Alternatively, the test can also be run using atest command.
+
+```
+atest AmrwbEncoderTest -- --enable-module-dynamic-download=true
 ```
diff --git a/media/libstagefright/codecs/m4v_h263/dec/test/AndroidTest.xml b/media/libstagefright/codecs/m4v_h263/dec/test/AndroidTest.xml
new file mode 100755
index 0000000..47e10ca
--- /dev/null
+++ b/media/libstagefright/codecs/m4v_h263/dec/test/AndroidTest.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<configuration description="Test module config for Mpeg4H263 Decoder unit tests">
+    <option name="test-suite-tag" value="Mpeg4H263DecoderTest" />
+    <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+        <option name="cleanup" value="true" />
+        <option name="push" value="Mpeg4H263DecoderTest->/data/local/tmp/Mpeg4H263DecoderTest" />
+        <option name="push-file"
+            key="https://storage.googleapis.com/android_media/frameworks/av/media/libstagefright/codecs/m4v_h263/dec/test/Mpeg4H263Decoder.zip?unzip=true"
+            value="/data/local/tmp/Mpeg4H263DecoderTestRes/" />
+    </target_preparer>
+
+    <test class="com.android.tradefed.testtype.GTest" >
+        <option name="native-test-device-path" value="/data/local/tmp" />
+        <option name="module-name" value="Mpeg4H263DecoderTest" />
+        <option name="native-test-flag" value="-P /data/local/tmp/Mpeg4H263DecoderTestRes/" />
+    </test>
+</configuration>
diff --git a/media/libstagefright/codecs/m4v_h263/dec/test/README.md b/media/libstagefright/codecs/m4v_h263/dec/test/README.md
index 3f46529..7e4aea1 100644
--- a/media/libstagefright/codecs/m4v_h263/dec/test/README.md
+++ b/media/libstagefright/codecs/m4v_h263/dec/test/README.md
@@ -22,13 +22,18 @@
 adb push ${OUT}/data/nativetest/Mpeg4H263DecoderTest/Mpeg4H263DecoderTest /data/local/tmp/
 ```
 
-The resource file for the tests is taken from [here](https://drive.google.com/drive/folders/13cM4tAaVFrmr-zGFqaAzFBbKs75pnm9b).
-Download Mpeg4H263Decoder folder and push all the files in this folder to /data/local/tmp/ on the device for testing.
+The resource file for the tests is taken from [here](https://storage.googleapis.com/android_media/frameworks/av/media/libstagefright/codecs/m4v_h263/dec/test/Mpeg4H263Decoder.zip). Download, unzip and push these files into device for testing.
+
 ```
-adb push Mpeg4H263Decoder/. /data/local/tmp/
+adb push Mpeg4H263Decoder /data/local/tmp/
 ```
 
 usage: Mpeg4H263DecoderTest -P \<path_to_folder\>
 ```
-adb shell /data/local/tmp/Mpeg4H263DecoderTest -P /data/local/tmp/
+adb shell /data/local/tmp/Mpeg4H263DecoderTest -P /data/local/tmp/Mpeg4H263Decoder/
+```
+Alternatively, the test can also be run using atest command.
+
+```
+atest Mpeg4H263DecoderTest -- --enable-module-dynamic-download=true
 ```
diff --git a/media/libstagefright/codecs/m4v_h263/enc/test/Android.bp b/media/libstagefright/codecs/m4v_h263/enc/test/Android.bp
new file mode 100644
index 0000000..b9a8117
--- /dev/null
+++ b/media/libstagefright/codecs/m4v_h263/enc/test/Android.bp
@@ -0,0 +1,45 @@
+/*
+ * 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.
+ */
+
+cc_test {
+    name: "Mpeg4H263EncoderTest",
+    gtest: true,
+
+    srcs : [ "Mpeg4H263EncoderTest.cpp" ],
+
+    shared_libs: [
+        "libutils",
+        "liblog",
+    ],
+
+    static_libs: [
+        "libstagefright_m4vh263enc",
+    ],
+
+    cflags: [
+        "-DOSCL_IMPORT_REF=",
+        "-Wall",
+        "-Werror",
+    ],
+
+    sanitize: {
+        misc_undefined: [
+            "signed-integer-overflow",
+            "unsigned-integer-overflow",
+        ],
+        cfi: true,
+    },
+}
diff --git a/media/libstagefright/codecs/m4v_h263/enc/test/AndroidTest.xml b/media/libstagefright/codecs/m4v_h263/enc/test/AndroidTest.xml
new file mode 100644
index 0000000..5218932
--- /dev/null
+++ b/media/libstagefright/codecs/m4v_h263/enc/test/AndroidTest.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<configuration description="Test module config for MPEG4H263 encoder unit tests">
+    <option name="test-suite-tag" value="Mpeg4H263EncoderTest" />
+    <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+        <option name="cleanup" value="true" />
+        <option name="push" value="Mpeg4H263EncoderTest->/data/local/tmp/Mpeg4H263EncoderTest/" />
+        <option name="push-file"
+            key="https://storage.googleapis.com/android_media/frameworks/av/media/libstagefright/codecs/m4v_h263/enc/test/Mpeg4H263Encoder.zip?unzip=true"
+            value="/data/local/tmp/Mpeg4H263EncoderTestRes/" />
+    </target_preparer>
+
+    <test class="com.android.tradefed.testtype.GTest" >
+        <option name="native-test-device-path" value="/data/local/tmp" />
+        <option name="module-name" value="Mpeg4H263EncoderTest" />
+        <option name="native-test-flag" value="-P /data/local/tmp/Mpeg4H263EncoderTestRes/" />
+    </test>
+</configuration>
\ No newline at end of file
diff --git a/media/libstagefright/codecs/m4v_h263/enc/test/Mpeg4H263EncoderTest.cpp b/media/libstagefright/codecs/m4v_h263/enc/test/Mpeg4H263EncoderTest.cpp
new file mode 100644
index 0000000..78c705a
--- /dev/null
+++ b/media/libstagefright/codecs/m4v_h263/enc/test/Mpeg4H263EncoderTest.cpp
@@ -0,0 +1,250 @@
+/*
+ * 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "Mpeg4H263EncoderTest"
+#include <utils/Log.h>
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+
+#include "mp4enc_api.h"
+
+#include "Mpeg4H263EncoderTestEnvironment.h"
+
+#define ENCODED_FILE "/data/local/tmp/Mpeg4H263Output"
+
+// assuming a worst case compression of 2X
+constexpr int16_t kCompressionRatio = 2;
+constexpr int8_t kIDRFrameRefreshIntervalInSec = 1;
+
+static Mpeg4H263EncoderTestEnvironment *gEnv = nullptr;
+
+class Mpeg4H263EncoderTest
+    : public ::testing::TestWithParam<tuple<string, bool, int32_t, int32_t, float, int32_t>> {
+  private:
+    void initEncoderParams();
+
+  public:
+    Mpeg4H263EncoderTest()
+        : mInputBuffer(nullptr),
+          mOutputBuffer(nullptr),
+          mFpInput(nullptr),
+          mFpOutput(nullptr),
+          mEncodeHandle(nullptr),
+          mEncodeControl(nullptr) {}
+
+    ~Mpeg4H263EncoderTest() {
+        if(mFpInput) {
+            fclose(mFpInput);
+        }
+        if(mFpOutput) {
+            fclose(mFpOutput);
+        }
+        if(mInputBuffer) free(mInputBuffer);
+        if(mOutputBuffer) free(mOutputBuffer);
+        if(mEncodeHandle) free(mEncodeHandle);
+        if(mEncodeControl) free(mEncodeControl);
+    }
+
+    void SetUp() override {
+        tuple<string /* fileName */, bool /* isMpeg4 */, int32_t /* frameWidth */,
+          int32_t /* frameHeight */, float /* frameRate */, int32_t /* bitRate */>
+            params = GetParam();
+        mFileName = gEnv->getRes() + get<0>(params);
+        mIsMpeg4 = get<1>(params);
+        mFrameWidth = get<2>(params);
+        mFrameHeight = get<3>(params);
+        mFrameRate = get<4>(params);
+        mBitRate = get<5>(params);
+
+        ASSERT_TRUE(mFrameWidth % 16 == 0) << "Frame Width should be multiple of 16";
+        ASSERT_TRUE(mFrameHeight % 16 == 0) << "Frame Height should be multiple of 16";
+        ASSERT_LE(mFrameWidth, (mIsMpeg4 ? 720 : 352))
+                << "Frame Width <= 720 for Mpeg4 and <= 352 for H263";
+        ASSERT_LE(mFrameHeight, (mIsMpeg4 ? 480 : 288))
+                << "Frame Height <= 480 for Mpeg4 and <= 288 for H263";
+        ASSERT_LE(mFrameRate, 30) << "Frame rate less than or equal to 30";
+        ASSERT_LE(mBitRate, 2048) << "Bit rate less than or equal to 2048 kbps";
+
+        mOutputBufferSize = ( mFrameWidth * mFrameHeight * 3/2 ) / kCompressionRatio;
+        mEncodeHandle = new VideoEncOptions;
+        ASSERT_NE(mEncodeHandle, nullptr) << "Failed to get Video Encoding options object";
+        memset(mEncodeHandle, 0, sizeof(VideoEncOptions));
+        mEncodeControl = new VideoEncControls;
+        ASSERT_NE(mEncodeControl, nullptr) << "Failed to get Video Encoding control object";
+        memset(mEncodeControl, 0, sizeof(VideoEncControls));
+        ASSERT_NO_FATAL_FAILURE(initEncoderParams())
+                << "Failed to get the default Encoding parameters!";
+    }
+
+    int64_t getTotalFrames();
+    void processEncoder(int32_t);
+    bool mIsMpeg4;
+    int32_t mFrameWidth, mFrameHeight, mBitRate;
+    int64_t mOutputBufferSize;
+    float mFrameRate;
+    string mFileName;
+    uint8_t *mInputBuffer, *mOutputBuffer;
+    FILE *mFpInput, *mFpOutput;
+    VideoEncOptions *mEncodeHandle;
+    VideoEncControls *mEncodeControl;
+};
+
+void Mpeg4H263EncoderTest::initEncoderParams() {
+    bool status = PVGetDefaultEncOption(mEncodeHandle, 0);
+    ASSERT_TRUE(status);
+
+    mEncodeHandle->rcType = VBR_1;
+    mEncodeHandle->vbvDelay = 5.0f;
+    mEncodeHandle->profile_level = CORE_PROFILE_LEVEL2;
+    mEncodeHandle->packetSize = 32;
+    mEncodeHandle->rvlcEnable = PV_OFF;
+    mEncodeHandle->numLayers = 1;
+    mEncodeHandle->timeIncRes = 1000;
+    mEncodeHandle->iQuant[0] = 15;
+    mEncodeHandle->pQuant[0] = 12;
+    mEncodeHandle->quantType[0] = 0;
+    mEncodeHandle->noFrameSkipped = PV_OFF;
+    mEncodeHandle->numIntraMB = 0;
+    mEncodeHandle->sceneDetect = PV_ON;
+    mEncodeHandle->searchRange = 16;
+    mEncodeHandle->mv8x8Enable = PV_OFF;
+    mEncodeHandle->gobHeaderInterval = 0;
+    mEncodeHandle->useACPred = PV_ON;
+    mEncodeHandle->intraDCVlcTh = 0;
+    if(!mIsMpeg4) {
+        mEncodeHandle->encMode = H263_MODE;
+    } else {
+        mEncodeHandle->encMode = COMBINE_MODE_WITH_ERR_RES;
+    }
+    mEncodeHandle->encWidth[0] = mFrameWidth;
+    mEncodeHandle->encHeight[0] = mFrameHeight;
+    mEncodeHandle->encFrameRate[0] = mFrameRate;
+    mEncodeHandle->bitRate[0] = mBitRate * 1024;
+    mEncodeHandle->tickPerSrc = mEncodeHandle->timeIncRes / mFrameRate;
+    if (kIDRFrameRefreshIntervalInSec == 0) {
+        // All I frames.
+        mEncodeHandle->intraPeriod = 1;
+    } else {
+        mEncodeHandle->intraPeriod = (kIDRFrameRefreshIntervalInSec * mFrameRate);
+    }
+}
+
+int64_t Mpeg4H263EncoderTest::getTotalFrames() {
+    int32_t frameSize = (mFrameWidth * mFrameHeight * 3) / 2;
+    struct stat buf;
+    stat(mFileName.c_str(), &buf);
+    size_t fileSize = buf.st_size;
+    int64_t totalFrames = (int64_t)(fileSize/frameSize);
+    return totalFrames;
+}
+
+void Mpeg4H263EncoderTest::processEncoder(int32_t numFramesToEncode) {
+    bool status;
+    int64_t numEncodedFrames = 0;
+    int32_t bytesRead;
+    int32_t frameSize = (mFrameWidth * mFrameHeight * 3) / 2;
+    while(numFramesToEncode != 0) {
+        bytesRead = fread(mInputBuffer, 1, frameSize, mFpInput);
+        // End of file.
+        if (bytesRead != frameSize) {
+            break;
+        }
+
+        VideoEncFrameIO videoIn, videoOut;
+        videoIn.height = mFrameHeight;
+        videoIn.pitch = mFrameWidth;
+        videoIn.timestamp = (numEncodedFrames * 1000) / mFrameRate;  // in ms.
+        videoIn.yChan = mInputBuffer;
+        videoIn.uChan = videoIn.yChan + videoIn.height * videoIn.pitch;
+        videoIn.vChan = videoIn.uChan + ((videoIn.height * videoIn.pitch) >> 2);
+        uint32_t modTimeMs = 0;
+        int32_t dataLength = mOutputBufferSize;
+        int32_t nLayer = 0;
+        status = PVEncodeVideoFrame(mEncodeControl, &videoIn, &videoOut, &modTimeMs, mOutputBuffer,
+                                    &dataLength, &nLayer);
+        ASSERT_TRUE(status) << "Failed to Encode: " << mFileName;
+
+        MP4HintTrack hintTrack;
+        status = PVGetHintTrack(mEncodeControl, &hintTrack);
+        ASSERT_TRUE(status) << "Failed to get hint track!";
+        UChar *overrunBuffer = PVGetOverrunBuffer(mEncodeControl);
+        ASSERT_EQ(overrunBuffer, nullptr) << "Overrun of buffer!";
+
+        int64_t numBytes = fwrite(mOutputBuffer, 1, dataLength, mFpOutput);
+        ASSERT_EQ(numBytes, dataLength) << "Failed to write to the output file!";
+        numEncodedFrames++;
+        numFramesToEncode--;
+    }
+}
+
+TEST_P(Mpeg4H263EncoderTest, EncodeTest) {
+    mInputBuffer = (uint8_t *)malloc((mFrameWidth * mFrameWidth * 3) / 2);
+    ASSERT_NE(mInputBuffer, nullptr) << "Failed to allocate the input buffer!";
+
+    mOutputBuffer = (uint8_t *)malloc(mOutputBufferSize);
+    ASSERT_NE(mOutputBuffer, nullptr) << "Failed to allocate the output buffer!";
+
+    mFpInput = fopen(mFileName.c_str(), "rb");
+    ASSERT_NE(mFpInput, nullptr) << "Failed to open the input file: " << mFileName;
+
+    mFpOutput = fopen(ENCODED_FILE, "wb");
+    ASSERT_NE(mFpOutput, nullptr) << "Failed to open the output file:" << ENCODED_FILE;
+
+    bool status = PVInitVideoEncoder(mEncodeControl, mEncodeHandle);
+    ASSERT_TRUE(status) << "Failed to initialize the encoder!";
+
+    // Get VOL header.
+    int32_t size = mOutputBufferSize;
+    status = PVGetVolHeader(mEncodeControl, mOutputBuffer, &size, 0);
+    ASSERT_TRUE(status) << "Failed to get the VOL header!";
+
+    // Write the VOL header on the first frame.
+    int32_t numBytes = fwrite(mOutputBuffer, 1, size, mFpOutput);
+    ASSERT_EQ(numBytes, size) << "Failed to write the VOL header!";
+
+    int64_t totalFrames = getTotalFrames();
+    ASSERT_NO_FATAL_FAILURE(processEncoder(totalFrames)) << "Failed to Encode: " << mFileName;
+    status = PVCleanUpVideoEncoder(mEncodeControl);
+    ASSERT_TRUE(status) << "Failed to clean up the encoder resources!";
+}
+
+INSTANTIATE_TEST_SUITE_P(
+        EncodeTest, Mpeg4H263EncoderTest,
+        ::testing::Values(
+                make_tuple("bbb_352x288_420p_30fps_32frames.yuv", false, 352, 288, 25, 1024),
+                make_tuple("bbb_352x288_420p_30fps_32frames.yuv", true, 352, 288, 25, 1024),
+                make_tuple("bbb_352x288_420p_30fps_32frames.yuv", false, 176, 144, 25, 1024),
+                make_tuple("bbb_352x288_420p_30fps_32frames.yuv", true, 176, 144, 25, 1024),
+                make_tuple("football_qvga.yuv", false, 352, 288, 25, 1024),
+                make_tuple("football_qvga.yuv", true, 352, 288, 25, 1024),
+                make_tuple("football_qvga.yuv", false, 176, 144, 30, 1024),
+                make_tuple("football_qvga.yuv", true, 176, 144, 30, 1024)));
+
+int32_t main(int argc, char **argv) {
+    gEnv = new Mpeg4H263EncoderTestEnvironment();
+    ::testing::AddGlobalTestEnvironment(gEnv);
+    ::testing::InitGoogleTest(&argc, argv);
+    uint8_t status = gEnv->initFromOptions(argc, argv);
+    if (status == 0) {
+        status = RUN_ALL_TESTS();
+        ALOGI("Encoder Test Result = %d\n", status);
+    }
+    return status;
+}
diff --git a/media/libstagefright/codecs/m4v_h263/enc/test/Mpeg4H263EncoderTestEnvironment.h b/media/libstagefright/codecs/m4v_h263/enc/test/Mpeg4H263EncoderTestEnvironment.h
new file mode 100644
index 0000000..7ee36e0
--- /dev/null
+++ b/media/libstagefright/codecs/m4v_h263/enc/test/Mpeg4H263EncoderTestEnvironment.h
@@ -0,0 +1,73 @@
+/*
+ * 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.
+ */
+
+#ifndef __MPEG4_H263_ENCODER_TEST_ENVIRONMENT_H__
+#define __MPEG4_H263_ENCODER_TEST_ENVIRONMENT_H__
+
+#include <gtest/gtest.h>
+
+#include <getopt.h>
+
+using namespace std;
+
+class Mpeg4H263EncoderTestEnvironment : public::testing::Environment {
+  public:
+    Mpeg4H263EncoderTestEnvironment() : res("/data/local/tmp/Mpeg4H263EncoderTest/") {}
+
+    // Parses the command line arguments
+    int initFromOptions(int argc, char **argv);
+
+    void setRes(const char *_res) { res = _res; }
+
+    const string getRes() const { return res; }
+
+  private:
+    string res;
+};
+
+int Mpeg4H263EncoderTestEnvironment::initFromOptions(int argc, char **argv) {
+    static struct option options[] = {{"path", required_argument, 0, 'P'}, {0, 0, 0, 0}};
+
+    while (true) {
+        int index = 0;
+        int c = getopt_long(argc, argv, "P:", options, &index);
+        if (c == -1) {
+            break;
+        }
+
+        switch (c) {
+            case 'P': {
+                setRes(optarg);
+                break;
+            }
+            default:
+                break;
+        }
+    }
+
+    if (optind < argc) {
+        fprintf(stderr,
+                "unrecognized option: %s\n\n"
+                "usage: %s <gtest options> <test options>\n\n"
+                "test options are:\n\n"
+                "-P, --path: Resource files directory location\n",
+                argv[optind ?: 1], argv[0]);
+        return 2;
+    }
+    return 0;
+}
+
+#endif  // __MPEG4_H263_ENCODER_TEST_ENVIRONMENT_H__
diff --git a/media/libstagefright/codecs/m4v_h263/enc/test/README.md b/media/libstagefright/codecs/m4v_h263/enc/test/README.md
new file mode 100644
index 0000000..25de878
--- /dev/null
+++ b/media/libstagefright/codecs/m4v_h263/enc/test/README.md
@@ -0,0 +1,38 @@
+## Media Testing ##
+---
+
+#### Mpeg4H263Encoder :
+The Mpeg4H263Encoder Test Suite validates the Mpeg4 and H263 encoder available in libstagefright.
+Run the following steps to build the test suite:
+```
+m Mpeg4H263EncoderTest
+```
+
+The 32-bit binaries will be created in the following path : ${OUT}/data/nativetest/
+The 64-bit binaries will be created in the following path : ${OUT}/data/nativetest64/
+
+To test 64-bit binary push binaries from nativetest64.
+```
+adb push ${OUT}/data/nativetest64/Mpeg4H263EncoderTest/Mpeg4H263EncoderTest /data/local/tmp/
+```
+
+To test 32-bit binary push binaries from nativetest.
+```
+adb push ${OUT}/data/nativetest/Mpeg4H263EncoderTest/Mpeg4H263EncoderTest /data/local/tmp/
+```
+
+The resource file for the tests is taken from [here](https://storage.googleapis.com/android_media/frameworks/av/media/libstagefright/codecs/m4v_h263/enc/test/Mpeg4H263Encoder.zip ) Download, unzip and push these files into device for testing.
+
+```
+adb push Mpeg4H263Encoder/. /data/local/tmp/
+```
+
+usage: Mpeg4H263EncoderTest -P \<path_to_folder\>
+```
+adb shell /data/local/tmp/Mpeg4H263EncoderTest -P /data/local/tmp/
+```
+Alternatively, the test can also be run using atest command.
+
+```
+atest Mpeg4H263EncoderTest -- --enable-module-dynamic-download=true
+```
diff --git a/media/libstagefright/codecs/mp3dec/test/AndroidTest.xml b/media/libstagefright/codecs/mp3dec/test/AndroidTest.xml
new file mode 100644
index 0000000..7ff9732
--- /dev/null
+++ b/media/libstagefright/codecs/mp3dec/test/AndroidTest.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<configuration description="Test module config for Mp3 Decoder unit test">
+    <option name="test-suite-tag" value="Mp3DecoderTest" />
+    <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+        <option name="cleanup" value="true" />
+        <option name="push" value="Mp3DecoderTest->/data/local/tmp/Mp3DecoderTest" />
+        <option name="push-file"
+            key="https://storage.googleapis.com/android_media/frameworks/av/media/libstagefright/mp3dec/test/Mp3DecoderTest.zip?unzip=true"
+            value="/data/local/tmp/Mp3DecoderTestRes/" />
+    </target_preparer>
+
+    <test class="com.android.tradefed.testtype.GTest" >
+        <option name="native-test-device-path" value="/data/local/tmp" />
+        <option name="module-name" value="Mp3DecoderTest" />
+        <option name="native-test-flag" value="-P /data/local/tmp/Mp3DecoderTestRes/" />
+    </test>
+</configuration>
diff --git a/media/libstagefright/codecs/mp3dec/test/README.md b/media/libstagefright/codecs/mp3dec/test/README.md
index 019239e..f59fec7 100644
--- a/media/libstagefright/codecs/mp3dec/test/README.md
+++ b/media/libstagefright/codecs/mp3dec/test/README.md
@@ -22,13 +22,18 @@
 adb push ${OUT}/data/nativetest/Mp3DecoderTest/Mp3DecoderTest /data/local/tmp/
 ```
 
-The resource file for the tests is taken from [here](https://drive.google.com/drive/folders/13cM4tAaVFrmr-zGFqaAzFBbKs75pnm9b). Push these files into device for testing.
-Download mp3 folder and push all the files in this folder to /data/local/tmp/ on the device.
+The resource file for the tests is taken from [here](https://storage.googleapis.com/android_media/frameworks/av/media/libstagefright/mp3dec/test/Mp3DecoderTest.zip). Download, unzip and push these files into device for testing.
+
 ```
-adb push mp3/. /data/local/tmp/
+adb push Mp3DecoderTestRes/. /data/local/tmp/
 ```
 
 usage: Mp3DecoderTest -P \<path_to_folder\>
 ```
-adb shell /data/local/tmp/Mp3DecoderTest -P /data/local/tmp/
+adb shell /data/local/tmp/Mp3DecoderTest -P /data/local/tmp/Mp3DecoderTestRes/
+```
+Alternatively, the test can also be run using atest command.
+
+```
+atest Mp3DecoderTest -- --enable-module-dynamic-download=true
 ```
diff --git a/media/libstagefright/flac/dec/test/Android.bp b/media/libstagefright/flac/dec/test/Android.bp
new file mode 100644
index 0000000..70ca80a
--- /dev/null
+++ b/media/libstagefright/flac/dec/test/Android.bp
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+cc_test {
+    name: "FlacDecoderTest",
+    gtest: true,
+
+    srcs: [
+        "FlacDecoderTest.cpp",
+    ],
+
+    shared_libs: [
+        "liblog",
+    ],
+
+    static_libs: [
+        "libstagefright_flacdec",
+        "libFLAC",
+    ],
+
+    header_libs: [
+        "libstagefright_foundation_headers",
+    ],
+
+    cflags: [
+        "-Werror",
+        "-Wall",
+    ],
+
+    sanitize: {
+        misc_undefined: [
+            "unsigned-integer-overflow",
+            "signed-integer-overflow",
+        ],
+        cfi: true,
+    },
+}
diff --git a/media/libstagefright/flac/dec/test/AndroidTest.xml b/media/libstagefright/flac/dec/test/AndroidTest.xml
new file mode 100644
index 0000000..bebba8e
--- /dev/null
+++ b/media/libstagefright/flac/dec/test/AndroidTest.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<configuration description="Test module config for flac decoder unit tests">
+    <option name="test-suite-tag" value="FlacDecoderTest" />
+    <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+        <option name="cleanup" value="true" />
+        <option name="push" value="FlacDecoderTest->/data/local/tmp/FlacDecoderTest/" />
+        <option name="push-file"
+            key="https://storage.googleapis.com/android_media/frameworks/av/media/libstagefright/flac/dec/test/FlacDecoder.zip?unzip=true"
+            value="/data/local/tmp/FlacDecoderTestRes/" />
+    </target_preparer>
+
+    <test class="com.android.tradefed.testtype.GTest" >
+        <option name="native-test-device-path" value="/data/local/tmp" />
+        <option name="module-name" value="FlacDecoderTest" />
+        <option name="native-test-flag" value="-P /data/local/tmp/FlacDecoderTestRes/" />
+    </test>
+</configuration>
\ No newline at end of file
diff --git a/media/libstagefright/flac/dec/test/FlacDecoderTest.cpp b/media/libstagefright/flac/dec/test/FlacDecoderTest.cpp
new file mode 100644
index 0000000..34f12db
--- /dev/null
+++ b/media/libstagefright/flac/dec/test/FlacDecoderTest.cpp
@@ -0,0 +1,270 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "FlacDecoderTest"
+
+#include <utils/Log.h>
+#include <fstream>
+
+#include "FLACDecoder.h"
+
+#include "FlacDecoderTestEnvironment.h"
+
+#define OUTPUT_FILE_NAME "/data/local/tmp/FlacDecoderOutput.raw"
+#define CODEC_CONFIG_FLAG 32
+
+constexpr uint32_t kMaxCount = 10;
+constexpr int32_t kMaxBlockSize = 4096;
+
+using namespace android;
+
+struct FrameInfo {
+    int32_t bytesCount;
+    uint32_t flags;
+    int64_t timestamp;
+};
+
+static FlacDecoderTestEnvironment *gEnv = nullptr;
+
+class FLACDecoderTest : public ::testing::TestWithParam<tuple<string, string, bool>> {
+  public:
+    FLACDecoderTest() : mFLACDecoder(nullptr), mHasStreamInfo(false), mInputBufferCount(0) {}
+
+    ~FLACDecoderTest() {
+        if (mEleStream.is_open()) mEleStream.close();
+        if (mFLACDecoder) delete mFLACDecoder;
+        mFLACDecoder = nullptr;
+    }
+
+    virtual void SetUp() override {
+        mFLACDecoder = FLACDecoder::Create();
+        ASSERT_NE(mFLACDecoder, nullptr) << "initDecoder: failed to create FLACDecoder";
+    }
+
+    int32_t processFlacDecoder(vector<FrameInfo> Info, int32_t offset, int32_t range,
+                               bool outputFloat, ofstream &ostrm);
+
+    FLACDecoder *mFLACDecoder;
+    FLAC__StreamMetadata_StreamInfo mStreamInfo;
+
+    bool mHasStreamInfo;
+    int32_t mInputBufferCount;
+    ifstream mEleStream;
+};
+
+void getInfo(string infoFileName, vector<FrameInfo> &Info) {
+    ifstream eleInfo;
+    eleInfo.open(infoFileName);
+    ASSERT_EQ(eleInfo.is_open(), true);
+    int32_t bytesCount = 0;
+    uint32_t flags = 0;
+    uint32_t timestamp = 0;
+    while (1) {
+        if (!(eleInfo >> bytesCount)) break;
+        eleInfo >> flags;
+        eleInfo >> timestamp;
+        Info.push_back({bytesCount, flags, timestamp});
+    }
+    if (eleInfo.is_open()) eleInfo.close();
+}
+
+int32_t FLACDecoderTest::processFlacDecoder(vector<FrameInfo> Info, int32_t offset, int32_t range,
+                                            bool outputFloat, ofstream &ostrm) {
+    memset(&mStreamInfo, 0, sizeof(mStreamInfo));
+
+    int32_t frameID = offset;
+    if (range + offset > Info.size() || range < 0 || offset > Info.size() - 1 || offset < 0) {
+        ALOGE("Invalid offset or range or both passed for decoding");
+        ALOGE("offset = %d \t range = %d  \t Info.size() = %zu", offset, range, Info.size());
+        return -1;
+    }
+
+    while (1) {
+        if (frameID == Info.size() || frameID == (offset + range)) break;
+        int64_t flags = (Info)[frameID].flags;
+        int32_t size = (Info)[frameID].bytesCount;
+        if (size < 0) {
+            ALOGE("Size for the memory allocation is negative");
+            return -1;
+        }
+        char *data = (char *)malloc(size);
+        if (!data) {
+            ALOGE("Insufficient memory to read frame");
+            return -1;
+        }
+
+        mEleStream.read(data, size);
+        if (mEleStream.gcount() != size) {
+            if (data) {
+                free(data);
+                data = nullptr;
+            }
+            ALOGE("Invalid size read, requested: %d and read: %zu", size, mEleStream.gcount());
+            return -1;
+        }
+
+        if (flags == CODEC_CONFIG_FLAG && mInputBufferCount == 0) {
+            status_t decoderErr = mFLACDecoder->parseMetadata((uint8_t *)data, size);
+            if (decoderErr == WOULD_BLOCK) {
+                ALOGV("process: parseMetadata is Blocking, Continue %d", decoderErr);
+            } else if (decoderErr == OK) {
+                mStreamInfo = mFLACDecoder->getStreamInfo();
+                if (mStreamInfo.sample_rate && mStreamInfo.max_blocksize && mStreamInfo.channels) {
+                    mHasStreamInfo = true;
+                }
+                ALOGV("decoder configuration : %d Hz, %d channels, %d samples,"
+                      " %d block size",
+                      mStreamInfo.sample_rate, mStreamInfo.channels,
+                      (int32_t)mStreamInfo.total_samples, mStreamInfo.max_blocksize);
+            } else {
+                ALOGE("FLACDecoder parseMetaData returns error %d", decoderErr);
+                if (data) {
+                    free(data);
+                    data = nullptr;
+                }
+                return decoderErr;
+            }
+        } else {
+            const size_t sampleSize = outputFloat ? sizeof(float) : sizeof(int16_t);
+            size_t outSize = mHasStreamInfo
+                                     ? mStreamInfo.max_blocksize * mStreamInfo.channels * sampleSize
+                                     : kMaxBlockSize * FLACDecoder::kMaxChannels * sampleSize;
+
+            void *out_buf = malloc(outSize);
+            if (!out_buf) {
+                if (data) {
+                    free(data);
+                    data = nullptr;
+                }
+                ALOGE("Output buffer allocation failed");
+                return -1;
+            }
+            status_t decoderErr = mFLACDecoder->decodeOneFrame((uint8_t *)data, size, out_buf,
+                                                               &outSize, outputFloat);
+            if (decoderErr != OK) {
+                ALOGE("decodeOneFrame returns error %d", decoderErr);
+                if (data) {
+                    free(data);
+                    data = nullptr;
+                }
+                if (out_buf) {
+                    free(out_buf);
+                    out_buf = nullptr;
+                }
+                return decoderErr;
+            }
+            ostrm.write(reinterpret_cast<char *>(out_buf), outSize);
+            free(out_buf);
+            out_buf = nullptr;
+        }
+        mInputBufferCount++;
+        frameID++;
+        free(data);
+        data = nullptr;
+    }
+    ALOGV("frameID=%d", frameID);
+    return 0;
+}
+
+TEST_F(FLACDecoderTest, CreateDeleteTest) {
+    if (mFLACDecoder) delete mFLACDecoder;
+    mFLACDecoder = nullptr;
+
+    for (int32_t i = 0; i < kMaxCount; i++) {
+        mFLACDecoder = FLACDecoder::Create();
+        ASSERT_NE(mFLACDecoder, nullptr) << "FLACDecoder Creation Failed";
+        if (mFLACDecoder) delete mFLACDecoder;
+        mFLACDecoder = nullptr;
+    }
+}
+
+TEST_P(FLACDecoderTest, FlushTest) {
+    tuple<string /* InputFileName */, string /* InfoFileName */, bool /* outputfloat */> params =
+            GetParam();
+
+    string inputFileName = gEnv->getRes() + get<0>(params);
+    string infoFileName = gEnv->getRes() + get<1>(params);
+    bool outputFloat = get<2>(params);
+
+    vector<FrameInfo> Info;
+    getInfo(infoFileName, Info);
+
+    mEleStream.open(inputFileName, ifstream::binary);
+    ASSERT_EQ(mEleStream.is_open(), true);
+
+    ofstream ostrm;
+    ostrm.open(OUTPUT_FILE_NAME, std::ofstream::binary);
+    ASSERT_EQ(ostrm.is_open(), true);
+
+    int32_t status = processFlacDecoder(Info, 0, Info.size() / 3, outputFloat, ostrm);
+    ASSERT_EQ(status, 0) << "Test Failed. Decode returned error = " << status << endl;
+    mFLACDecoder->flush();
+    mHasStreamInfo = false;
+    status = processFlacDecoder(Info, (Info.size() / 3), Info.size() - (Info.size() / 3),
+                                outputFloat, ostrm);
+    ostrm.close();
+    Info.clear();
+    ASSERT_EQ(status, 0) << "Test Failed. Decode returned error = " << status << endl;
+}
+
+TEST_P(FLACDecoderTest, DecodeTest) {
+    tuple<string /* InputFileName */, string /* InfoFileName */, bool /* outputfloat */> params =
+            GetParam();
+
+    string inputFileName = gEnv->getRes() + get<0>(params);
+    string infoFileName = gEnv->getRes() + get<1>(params);
+    bool outputFloat = get<2>(params);
+
+    vector<FrameInfo> Info;
+    getInfo(infoFileName, Info);
+
+    mEleStream.open(inputFileName, ifstream::binary);
+    ASSERT_EQ(mEleStream.is_open(), true);
+
+    ofstream ostrm;
+    ostrm.open(OUTPUT_FILE_NAME, std::ofstream::binary);
+    ASSERT_EQ(ostrm.is_open(), true);
+
+    int32_t status = processFlacDecoder(Info, 0, Info.size(), outputFloat, ostrm);
+    ostrm.close();
+    Info.clear();
+    ASSERT_EQ(status, 0) << "Test Failed. Decode returned error = " << status << endl;
+}
+
+// TODO: Add remaining tests
+INSTANTIATE_TEST_SUITE_P(
+        FLACDecoderTestAll, FLACDecoderTest,
+        ::testing::Values(make_tuple("bbb_flac_stereo_680kbps_48000hz.flac",
+                                     "bbb_flac_stereo_680kbps_48000hz.info", true),
+                          make_tuple("bbb_flac_stereo_680kbps_48000hz.flac",
+                                     "bbb_flac_stereo_680kbps_48000hz.info", false),
+                          make_tuple("bbb_flac_stereo_600kbps_44100hz.flac",
+                                     "bbb_flac_stereo_600kbps_44100hz.info", true),
+                          make_tuple("bbb_flac_stereo_600kbps_44100hz.flac",
+                                     "bbb_flac_stereo_600kbps_44100hz.info", false)));
+
+int main(int argc, char **argv) {
+    gEnv = new FlacDecoderTestEnvironment();
+    ::testing::AddGlobalTestEnvironment(gEnv);
+    ::testing::InitGoogleTest(&argc, argv);
+    int status = gEnv->initFromOptions(argc, argv);
+    if (status == 0) {
+        status = RUN_ALL_TESTS();
+        ALOGV("Flac Decoder Test Result = %d\n", status);
+    }
+    return status;
+}
diff --git a/media/libstagefright/flac/dec/test/FlacDecoderTestEnvironment.h b/media/libstagefright/flac/dec/test/FlacDecoderTestEnvironment.h
new file mode 100644
index 0000000..1334bba
--- /dev/null
+++ b/media/libstagefright/flac/dec/test/FlacDecoderTestEnvironment.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+#ifndef __FLAC_DECODER_TEST_ENVIRONMENT_H__
+#define __FLAC_DECODER_TEST_ENVIRONMENT_H__
+
+#include <gtest/gtest.h>
+
+#include <getopt.h>
+
+using namespace std;
+
+class FlacDecoderTestEnvironment : public ::testing::Environment {
+  public:
+    FlacDecoderTestEnvironment() : res("/data/local/tmp/") {}
+
+    // Parses the command line arguments
+    int initFromOptions(int argc, char **argv);
+
+    void setRes(const char *_res) { res = _res; }
+
+    const string getRes() const { return res; }
+
+  private:
+    string res;
+};
+
+int FlacDecoderTestEnvironment::initFromOptions(int argc, char **argv) {
+    static struct option options[] = {{"path", required_argument, 0, 'P'}, {0, 0, 0, 0}};
+
+    while (true) {
+        int index = 0;
+        int c = getopt_long(argc, argv, "P:", options, &index);
+        if (c == -1) {
+            break;
+        }
+
+        switch (c) {
+            case 'P': {
+                setRes(optarg);
+                break;
+            }
+            default:
+                break;
+        }
+    }
+
+    if (optind < argc) {
+        fprintf(stderr,
+                "unrecognized option: %s\n\n"
+                "usage: %s <gtest options> <test options>\n\n"
+                "test options are:\n\n"
+                "-P, --path: Resource files directory location\n",
+                argv[optind ?: 1], argv[0]);
+        return 2;
+    }
+    return 0;
+}
+
+#endif  // __FLAC_DECODER_TEST_ENVIRONMENT_H__
diff --git a/media/libstagefright/flac/dec/test/README.md b/media/libstagefright/flac/dec/test/README.md
new file mode 100644
index 0000000..4d194cd
--- /dev/null
+++ b/media/libstagefright/flac/dec/test/README.md
@@ -0,0 +1,40 @@
+## Media Testing ##
+---
+#### FlacDecoder :
+The FlacDecoder Test Suite validates the FlacDecoder available in libstagefright.
+
+Run the following steps to build the test suite:
+```
+m FlacDecoderTest
+```
+
+The 32-bit binaries will be created in the following path : ${OUT}/data/nativetest/
+
+The 64-bit binaries will be created in the following path : ${OUT}/data/nativetest64/
+
+To test 64-bit binary push binaries from nativetest64.
+```
+adb push ${OUT}/data/nativetest64/FlacDecoderTest/FlacDecoderTest /data/local/tmp/
+```
+
+To test 32-bit binary push binaries from nativetest.
+```
+adb push ${OUT}/data/nativetest/FlacDecoderTest/FlacDecoderTest /data/local/tmp/
+```
+
+The resource file for the tests is taken from [here](https://storage.googleapis.com/android_media/frameworks/av/media/libstagefright/flac/dec/test/FlacDecoder.zip).
+Download, unzip and push these files into device for testing.
+
+```
+adb push FlacDecoder /data/local/tmp/
+```
+
+usage: FlacDecoderTest -P \<path_to_folder\>
+```
+adb shell /data/local/tmp/FlacDecoderTest -P /data/local/tmp/FlacDecoder/
+```
+Alternatively, the test can also be run using atest command.
+
+```
+atest FlacDecoderTest -- --enable-module-dynamic-download=true
+```
diff --git a/media/libstagefright/id3/test/AndroidTest.xml b/media/libstagefright/id3/test/AndroidTest.xml
new file mode 100644
index 0000000..6c6697d
--- /dev/null
+++ b/media/libstagefright/id3/test/AndroidTest.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<configuration description="Test module config for ID3 unit tests">
+    <option name="test-suite-tag" value="ID3Test" />
+    <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+        <option name="cleanup" value="true" />
+        <option name="push" value="ID3Test->/data/local/tmp/ID3Test" />
+        <option name="push-file"
+            key="https://storage.googleapis.com/android_media/frameworks/av/media/libstagefright/id3/test/ID3Test.zip?unzip=true"
+            value="/data/local/tmp/ID3TestRes/" />
+    </target_preparer>
+
+    <test class="com.android.tradefed.testtype.GTest" >
+        <option name="native-test-device-path" value="/data/local/tmp" />
+        <option name="module-name" value="ID3Test" />
+        <option name="native-test-flag" value="-P /data/local/tmp/ID3TestRes/" />
+    </test>
+</configuration>
diff --git a/media/libstagefright/id3/test/README.md b/media/libstagefright/id3/test/README.md
index 72f730c..7fd8901 100644
--- a/media/libstagefright/id3/test/README.md
+++ b/media/libstagefright/id3/test/README.md
@@ -22,13 +22,19 @@
 adb push ${OUT}/data/nativetest/ID3Test/ID3Test /data/local/tmp/
 ```
 
-The resource file for the tests is taken from [here](https://drive.google.com/drive/folders/1pt5HFVSysbqfyqY1sVJ9MTupZKCdqjYZ). Push these files into device for testing.
-Download ID3 folder and push all the files in this folder to /data/local/tmp/ID3 on the device.
+The resource file for the tests is taken from [here](https://storage.googleapis.com/android_media/frameworks/av/media/libstagefright/id3/test/ID3Test.zip ).
+Download, unzip and push these files into device for testing.
+
 ```
-adb push ID3/. /data/local/tmp/ID3
+adb push ID3Test /data/local/tmp/
 ```
 
 usage: ID3Test -P \<path_to_folder\>
 ```
 adb shell /data/local/tmp/ID3Test -P /data/local/tmp/ID3/
 ```
+Alternatively, the test can also be run using atest command.
+
+```
+atest ID3Test -- --enable-module-dynamic-download=true
+```
diff --git a/media/tests/benchmark/MediaBenchmarkTest/src/main/cpp/Android.bp b/media/tests/benchmark/MediaBenchmarkTest/src/main/cpp/Android.bp
index c72eb55..3e5e4c8 100644
--- a/media/tests/benchmark/MediaBenchmarkTest/src/main/cpp/Android.bp
+++ b/media/tests/benchmark/MediaBenchmarkTest/src/main/cpp/Android.bp
@@ -1,5 +1,6 @@
 cc_test_library {
     name: "libmediabenchmark_jni",
+    sdk_version: "current",
 
     defaults: [
         "libmediabenchmark_common-defaults",
diff --git a/media/tests/benchmark/src/native/common/Android.bp b/media/tests/benchmark/src/native/common/Android.bp
index f8ea25c..d4389da 100644
--- a/media/tests/benchmark/src/native/common/Android.bp
+++ b/media/tests/benchmark/src/native/common/Android.bp
@@ -46,6 +46,8 @@
 
 cc_defaults {
     name: "libmediabenchmark-defaults",
+    sdk_version: "current",
+    stl: "c++_shared",
 
     shared_libs: [
         "libmediandk",
diff --git a/services/mediacodec/registrant/Android.bp b/services/mediacodec/registrant/Android.bp
index fa5bc4a..765ac99 100644
--- a/services/mediacodec/registrant/Android.bp
+++ b/services/mediacodec/registrant/Android.bp
@@ -14,6 +14,7 @@
         "libbase",
         "libcodec2_hidl@1.0",
         "libcodec2_vndk",
+        "libhidlbase",
         "libutils",
     ],
 
diff --git a/services/mediacodec/registrant/CodecServiceRegistrant.cpp b/services/mediacodec/registrant/CodecServiceRegistrant.cpp
index 706ebee..7f7ceca 100644
--- a/services/mediacodec/registrant/CodecServiceRegistrant.cpp
+++ b/services/mediacodec/registrant/CodecServiceRegistrant.cpp
@@ -18,21 +18,411 @@
 #define LOG_TAG "CodecServiceRegistrant"
 
 #include <android-base/logging.h>
+#include <android-base/properties.h>
 
+#include <C2Component.h>
 #include <C2PlatformSupport.h>
 #include <codec2/hidl/1.0/ComponentStore.h>
+#include <codec2/hidl/1.0/Configurable.h>
+#include <codec2/hidl/1.0/types.h>
+#include <hidl/HidlSupport.h>
 #include <media/CodecServiceRegistrant.h>
 
+namespace /* unnamed */ {
+
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::sp;
+using namespace ::android::hardware::media::c2::V1_0;
+using namespace ::android::hardware::media::c2::V1_0::utils;
+
+constexpr c2_status_t C2_TRANSACTION_FAILED = C2_CORRUPTED;
+
+// Converter from IComponentStore to C2ComponentStore.
+class H2C2ComponentStore : public C2ComponentStore {
+protected:
+    sp<IComponentStore> mStore;
+    sp<IConfigurable> mConfigurable;
+public:
+    explicit H2C2ComponentStore(sp<IComponentStore> const& store)
+          : mStore{store},
+            mConfigurable{[store]() -> sp<IConfigurable>{
+                if (!store) {
+                    return nullptr;
+                }
+                Return<sp<IConfigurable>> transResult =
+                    store->getConfigurable();
+                return transResult.isOk() ?
+                        static_cast<sp<IConfigurable>>(transResult) :
+                        nullptr;
+            }()} {
+        if (!mConfigurable) {
+            LOG(ERROR) << "Preferred store is corrupted.";
+        }
+    }
+
+    virtual ~H2C2ComponentStore() override = default;
+
+    virtual c2_status_t config_sm(
+            std::vector<C2Param*> const &params,
+            std::vector<std::unique_ptr<C2SettingResult>>* const failures
+            ) override {
+        Params hidlParams;
+        if (!createParamsBlob(&hidlParams, params)) {
+            LOG(ERROR) << "config -- bad input.";
+            return C2_TRANSACTION_FAILED;
+        }
+        c2_status_t status{};
+        Return<void> transResult = mConfigurable->config(
+                hidlParams,
+                true,
+                [&status, &params, failures](
+                        Status s,
+                        const hidl_vec<SettingResult> f,
+                        const Params& o) {
+                    status = static_cast<c2_status_t>(s);
+                    if (status != C2_OK && status != C2_BAD_INDEX) {
+                        LOG(DEBUG) << "config -- call failed: "
+                                   << status << ".";
+                    }
+                    size_t i = failures->size();
+                    failures->resize(i + f.size());
+                    for (const SettingResult& sf : f) {
+                        if (!objcpy(&(*failures)[i++], sf)) {
+                            LOG(ERROR) << "config -- "
+                                       << "invalid SettingResult returned.";
+                            return;
+                        }
+                    }
+                    if (!updateParamsFromBlob(params, o)) {
+                        LOG(ERROR) << "config -- "
+                                   << "failed to parse returned params.";
+                        status = C2_CORRUPTED;
+                    }
+                });
+        if (!transResult.isOk()) {
+            LOG(ERROR) << "config -- transaction failed.";
+            return C2_TRANSACTION_FAILED;
+        }
+        return status;
+    };
+
+    virtual c2_status_t copyBuffer(
+            std::shared_ptr<C2GraphicBuffer>,
+            std::shared_ptr<C2GraphicBuffer>) override {
+        LOG(ERROR) << "copyBuffer -- not supported.";
+        return C2_OMITTED;
+    }
+
+    virtual c2_status_t createComponent(
+            C2String, std::shared_ptr<C2Component> *const component) override {
+        component->reset();
+        LOG(ERROR) << "createComponent -- not supported.";
+        return C2_OMITTED;
+    }
+
+    virtual c2_status_t createInterface(
+            C2String, std::shared_ptr<C2ComponentInterface> *const interface) {
+        interface->reset();
+        LOG(ERROR) << "createInterface -- not supported.";
+        return C2_OMITTED;
+    }
+
+    virtual c2_status_t query_sm(
+            const std::vector<C2Param *> &stackParams,
+            const std::vector<C2Param::Index> &heapParamIndices,
+            std::vector<std::unique_ptr<C2Param>> *const heapParams) const
+            override {
+        hidl_vec<ParamIndex> indices(
+                stackParams.size() + heapParamIndices.size());
+        size_t numIndices = 0;
+        for (C2Param* const& stackParam : stackParams) {
+            if (!stackParam) {
+                LOG(WARNING) << "query -- null stack param encountered.";
+                continue;
+            }
+            indices[numIndices++] = static_cast<ParamIndex>(stackParam->index());
+        }
+        size_t numStackIndices = numIndices;
+        for (const C2Param::Index& index : heapParamIndices) {
+            indices[numIndices++] =
+                    static_cast<ParamIndex>(static_cast<uint32_t>(index));
+        }
+        indices.resize(numIndices);
+        if (heapParams) {
+            heapParams->reserve(heapParams->size() + numIndices);
+        }
+        c2_status_t status;
+        Return<void> transResult = mConfigurable->query(
+                indices,
+                true,
+                [&status, &numStackIndices, &stackParams, heapParams](
+                        Status s, const Params& p) {
+                    status = static_cast<c2_status_t>(s);
+                    if (status != C2_OK && status != C2_BAD_INDEX) {
+                        LOG(DEBUG) << "query -- call failed: "
+                                   << status << ".";
+                        return;
+                    }
+                    std::vector<C2Param*> paramPointers;
+                    if (!parseParamsBlob(&paramPointers, p)) {
+                        LOG(ERROR) << "query -- error while parsing params.";
+                        status = C2_CORRUPTED;
+                        return;
+                    }
+                    size_t i = 0;
+                    for (auto it = paramPointers.begin();
+                            it != paramPointers.end(); ) {
+                        C2Param* paramPointer = *it;
+                        if (numStackIndices > 0) {
+                            --numStackIndices;
+                            if (!paramPointer) {
+                                LOG(WARNING) << "query -- null stack param.";
+                                ++it;
+                                continue;
+                            }
+                            for (; i < stackParams.size() && !stackParams[i]; ) {
+                                ++i;
+                            }
+                            if (i >= stackParams.size()) {
+                                LOG(ERROR) << "query -- unexpected error.";
+                                status = C2_CORRUPTED;
+                                return;
+                            }
+                            if (stackParams[i]->index() != paramPointer->index()) {
+                                LOG(WARNING) << "query -- param skipped: "
+                                                "index = "
+                                             << stackParams[i]->index() << ".";
+                                stackParams[i++]->invalidate();
+                                continue;
+                            }
+                            if (!stackParams[i++]->updateFrom(*paramPointer)) {
+                                LOG(WARNING) << "query -- param update failed: "
+                                                "index = "
+                                             << paramPointer->index() << ".";
+                            }
+                        } else {
+                            if (!paramPointer) {
+                                LOG(WARNING) << "query -- null heap param.";
+                                ++it;
+                                continue;
+                            }
+                            if (!heapParams) {
+                                LOG(WARNING) << "query -- "
+                                                "unexpected extra stack param.";
+                            } else {
+                                heapParams->emplace_back(
+                                        C2Param::Copy(*paramPointer));
+                            }
+                        }
+                        ++it;
+                    }
+                });
+        if (!transResult.isOk()) {
+            LOG(ERROR) << "query -- transaction failed.";
+            return C2_TRANSACTION_FAILED;
+        }
+        return status;
+    }
+
+    virtual c2_status_t querySupportedParams_nb(
+            std::vector<std::shared_ptr<C2ParamDescriptor>> *const params) const {
+        c2_status_t status;
+        Return<void> transResult = mConfigurable->querySupportedParams(
+                std::numeric_limits<uint32_t>::min(),
+                std::numeric_limits<uint32_t>::max(),
+                [&status, params](
+                        Status s,
+                        const hidl_vec<ParamDescriptor>& p) {
+                    status = static_cast<c2_status_t>(s);
+                    if (status != C2_OK) {
+                        LOG(DEBUG) << "querySupportedParams -- call failed: "
+                                   << status << ".";
+                        return;
+                    }
+                    size_t i = params->size();
+                    params->resize(i + p.size());
+                    for (const ParamDescriptor& sp : p) {
+                        if (!objcpy(&(*params)[i++], sp)) {
+                            LOG(ERROR) << "querySupportedParams -- "
+                                       << "invalid returned ParamDescriptor.";
+                            return;
+                        }
+                    }
+                });
+        if (!transResult.isOk()) {
+            LOG(ERROR) << "querySupportedParams -- transaction failed.";
+            return C2_TRANSACTION_FAILED;
+        }
+        return status;
+    }
+
+    virtual c2_status_t querySupportedValues_sm(
+            std::vector<C2FieldSupportedValuesQuery> &fields) const {
+        hidl_vec<FieldSupportedValuesQuery> inFields(fields.size());
+        for (size_t i = 0; i < fields.size(); ++i) {
+            if (!objcpy(&inFields[i], fields[i])) {
+                LOG(ERROR) << "querySupportedValues -- bad input";
+                return C2_TRANSACTION_FAILED;
+            }
+        }
+
+        c2_status_t status;
+        Return<void> transResult = mConfigurable->querySupportedValues(
+                inFields,
+                true,
+                [&status, &inFields, &fields](
+                        Status s,
+                        const hidl_vec<FieldSupportedValuesQueryResult>& r) {
+                    status = static_cast<c2_status_t>(s);
+                    if (status != C2_OK) {
+                        LOG(DEBUG) << "querySupportedValues -- call failed: "
+                                   << status << ".";
+                        return;
+                    }
+                    if (r.size() != fields.size()) {
+                        LOG(ERROR) << "querySupportedValues -- "
+                                      "input and output lists "
+                                      "have different sizes.";
+                        status = C2_CORRUPTED;
+                        return;
+                    }
+                    for (size_t i = 0; i < fields.size(); ++i) {
+                        if (!objcpy(&fields[i], inFields[i], r[i])) {
+                            LOG(ERROR) << "querySupportedValues -- "
+                                          "invalid returned value.";
+                            status = C2_CORRUPTED;
+                            return;
+                        }
+                    }
+                });
+        if (!transResult.isOk()) {
+            LOG(ERROR) << "querySupportedValues -- transaction failed.";
+            return C2_TRANSACTION_FAILED;
+        }
+        return status;
+    }
+
+    virtual C2String getName() const {
+        C2String outName;
+        Return<void> transResult = mConfigurable->getName(
+                [&outName](const hidl_string& name) {
+                    outName = name.c_str();
+                });
+        if (!transResult.isOk()) {
+            LOG(ERROR) << "getName -- transaction failed.";
+        }
+        return outName;
+    }
+
+    virtual std::shared_ptr<C2ParamReflector> getParamReflector() const
+            override {
+        struct SimpleParamReflector : public C2ParamReflector {
+            virtual std::unique_ptr<C2StructDescriptor> describe(
+                    C2Param::CoreIndex coreIndex) const {
+                hidl_vec<ParamIndex> indices(1);
+                indices[0] = static_cast<ParamIndex>(coreIndex.coreIndex());
+                std::unique_ptr<C2StructDescriptor> descriptor;
+                Return<void> transResult = mBase->getStructDescriptors(
+                        indices,
+                        [&descriptor](
+                                Status s,
+                                const hidl_vec<StructDescriptor>& sd) {
+                            c2_status_t status = static_cast<c2_status_t>(s);
+                            if (status != C2_OK) {
+                                LOG(DEBUG) << "SimpleParamReflector -- "
+                                              "getStructDescriptors() failed: "
+                                           << status << ".";
+                                descriptor.reset();
+                                return;
+                            }
+                            if (sd.size() != 1) {
+                                LOG(DEBUG) << "SimpleParamReflector -- "
+                                              "getStructDescriptors() "
+                                              "returned vector of size "
+                                           << sd.size() << ". "
+                                              "It should be 1.";
+                                descriptor.reset();
+                                return;
+                            }
+                            if (!objcpy(&descriptor, sd[0])) {
+                                LOG(DEBUG) << "SimpleParamReflector -- "
+                                              "getStructDescriptors() returned "
+                                              "corrupted data.";
+                                descriptor.reset();
+                                return;
+                            }
+                        });
+                return descriptor;
+            }
+
+            explicit SimpleParamReflector(sp<IComponentStore> base)
+                : mBase(base) { }
+
+            sp<IComponentStore> mBase;
+        };
+
+        return std::make_shared<SimpleParamReflector>(mStore);
+    }
+
+    virtual std::vector<std::shared_ptr<const C2Component::Traits>>
+            listComponents() override {
+        LOG(ERROR) << "listComponents -- not supported.";
+        return {};
+    }
+};
+
+bool ionPropertiesDefined() {
+    using namespace ::android::base;
+    std::string heapMask =
+        GetProperty("ro.com.android.media.swcodec.ion.heapmask", "undefined");
+    std::string flags =
+        GetProperty("ro.com.android.media.swcodec.ion.flags", "undefined");
+    std::string align =
+        GetProperty("ro.com.android.media.swcodec.ion.align", "undefined");
+    if (heapMask != "undefined" ||
+            flags != "undefined" ||
+            align != "undefined") {
+        LOG(INFO)
+                << "Some system properties for mediaswcodec ION usage are set: "
+                << "heapmask = " << heapMask << ", "
+                << "flags = " << flags << ", "
+                << "align = " << align << ". "
+                << "Preferred Codec2 store is defaulted to \"software\".";
+        return true;
+    }
+    return false;
+}
+
+} // unnamed namespace
+
 extern "C" void RegisterCodecServices() {
-    using namespace ::android::hardware::media::c2::V1_0;
+    using ComponentStore = ::android::hardware::media::c2::V1_0::utils::
+            ComponentStore;
     LOG(INFO) << "Creating software Codec2 service...";
-    android::sp<IComponentStore> store =
-        new utils::ComponentStore(
-                android::GetCodec2PlatformComponentStore());
+    sp<ComponentStore> store =
+        new ComponentStore(::android::GetCodec2PlatformComponentStore());
     if (store == nullptr) {
         LOG(ERROR) <<
                 "Cannot create software Codec2 service.";
     } else {
+        if (!ionPropertiesDefined()) {
+            std::string preferredStoreName = "default";
+            sp<IComponentStore> preferredStore =
+                IComponentStore::getService(preferredStoreName.c_str());
+            if (preferredStore) {
+                ::android::SetPreferredCodec2ComponentStore(
+                        std::make_shared<H2C2ComponentStore>(preferredStore));
+                LOG(INFO) <<
+                        "Preferred Codec2 store is set to \"" <<
+                        preferredStoreName << "\".";
+            } else {
+                LOG(INFO) <<
+                        "Preferred Codec2 store is defaulted to \"software\".";
+            }
+        }
         if (store->registerAsService("software") != android::OK) {
             LOG(ERROR) <<
                     "Cannot register software Codec2 service.";