Merge "aaudio: initialize the callback buffer" into rvc-dev am: 398fe58cbc am: bde841108d am: 07a3ffa1e7 am: e9506dac8d

Change-Id: I5b8c183b143ab7b6c4bb6d0dc4858fc227d31fba
diff --git a/camera/CameraParameters.cpp b/camera/CameraParameters.cpp
index 68969cf..e95c91c 100644
--- a/camera/CameraParameters.cpp
+++ b/camera/CameraParameters.cpp
@@ -20,6 +20,7 @@
 
 #include <string.h>
 #include <stdlib.h>
+#include <unistd.h>
 #include <camera/CameraParameters.h>
 #include <system/graphics.h>
 
diff --git a/camera/CameraParameters2.cpp b/camera/CameraParameters2.cpp
index c29233c..a1cf355 100644
--- a/camera/CameraParameters2.cpp
+++ b/camera/CameraParameters2.cpp
@@ -21,6 +21,7 @@
 
 #include <string.h>
 #include <stdlib.h>
+#include <unistd.h>
 #include <camera/CameraParameters2.h>
 
 namespace android {
diff --git a/camera/ndk/impl/ACameraManager.cpp b/camera/ndk/impl/ACameraManager.cpp
index b58ebe2..419250c 100644
--- a/camera/ndk/impl/ACameraManager.cpp
+++ b/camera/ndk/impl/ACameraManager.cpp
@@ -743,7 +743,7 @@
     // No way to get package name from native.
     // Send a zero length package name and let camera service figure it out from UID
     binder::Status serviceRet = cs->connectDevice(
-            callbacks, String16(cameraId), String16(""), std::unique_ptr<String16>(),
+            callbacks, String16(cameraId), String16(""), {},
             hardware::ICameraService::USE_CALLING_UID, /*out*/&deviceRemote);
 
     if (!serviceRet.isOk()) {
diff --git a/camera/tests/CameraBinderTests.cpp b/camera/tests/CameraBinderTests.cpp
index 8ccded2..eee05ff 100644
--- a/camera/tests/CameraBinderTests.cpp
+++ b/camera/tests/CameraBinderTests.cpp
@@ -378,7 +378,7 @@
         sp<TestCameraDeviceCallbacks> callbacks(new TestCameraDeviceCallbacks());
         sp<hardware::camera2::ICameraDeviceUser> device;
         res = service->connectDevice(callbacks, cameraId, String16("meeeeeeeee!"),
-                std::unique_ptr<String16>(), hardware::ICameraService::USE_CALLING_UID,
+                {}, hardware::ICameraService::USE_CALLING_UID,
                 /*out*/&device);
         EXPECT_TRUE(res.isOk()) << res;
         ASSERT_NE(nullptr, device.get());
@@ -421,7 +421,7 @@
         {
             SCOPED_TRACE("openNewDevice");
             binder::Status res = service->connectDevice(callbacks, deviceId, String16("meeeeeeeee!"),
-                    std::unique_ptr<String16>(), hardware::ICameraService::USE_CALLING_UID,
+                    {}, hardware::ICameraService::USE_CALLING_UID,
                     /*out*/&device);
             EXPECT_TRUE(res.isOk()) << res;
         }
diff --git a/drm/libmediadrm/DrmSessionManager.cpp b/drm/libmediadrm/DrmSessionManager.cpp
index 5292705..e31395d 100644
--- a/drm/libmediadrm/DrmSessionManager.cpp
+++ b/drm/libmediadrm/DrmSessionManager.cpp
@@ -66,7 +66,7 @@
     std::vector<MediaResourceParcel> resources;
     MediaResourceParcel resource{
             Type::kDrmSession, SubType::kUnspecifiedSubType,
-            toStdVec<int8_t>(sessionId), value};
+            toStdVec<>(sessionId), value};
     resources.push_back(resource);
     return resources;
 }
diff --git a/media/codec2/components/g711/Android.bp b/media/codec2/components/g711/Android.bp
index 3ede68c..0101b1a 100644
--- a/media/codec2/components/g711/Android.bp
+++ b/media/codec2/components/g711/Android.bp
@@ -7,6 +7,8 @@
 
     srcs: ["C2SoftG711Dec.cpp"],
 
+    static_libs: ["codecs_g711dec"],
+
     cflags: [
         "-DALAW",
     ],
@@ -20,4 +22,6 @@
     ],
 
     srcs: ["C2SoftG711Dec.cpp"],
+
+    static_libs: ["codecs_g711dec"],
 }
diff --git a/media/codec2/components/g711/C2SoftG711Dec.cpp b/media/codec2/components/g711/C2SoftG711Dec.cpp
index 4ff0793..7f9c34e 100644
--- a/media/codec2/components/g711/C2SoftG711Dec.cpp
+++ b/media/codec2/components/g711/C2SoftG711Dec.cpp
@@ -22,7 +22,7 @@
 
 #include <C2PlatformSupport.h>
 #include <SimpleC2Interface.h>
-
+#include <g711Dec.h>
 #include "C2SoftG711Dec.h"
 
 namespace android {
@@ -224,53 +224,6 @@
     return C2_OK;
 }
 
-#ifdef ALAW
-void C2SoftG711Dec::DecodeALaw(
-        int16_t *out, const uint8_t *in, size_t inSize) {
-    while (inSize > 0) {
-        inSize--;
-        int32_t x = *in++;
-
-        int32_t ix = x ^ 0x55;
-        ix &= 0x7f;
-
-        int32_t iexp = ix >> 4;
-        int32_t mant = ix & 0x0f;
-
-        if (iexp > 0) {
-            mant += 16;
-        }
-
-        mant = (mant << 4) + 8;
-
-        if (iexp > 1) {
-            mant = mant << (iexp - 1);
-        }
-
-        *out++ = (x > 127) ? mant : -mant;
-    }
-}
-#else
-void C2SoftG711Dec::DecodeMLaw(
-        int16_t *out, const uint8_t *in, size_t inSize) {
-    while (inSize > 0) {
-        inSize--;
-        int32_t x = *in++;
-
-        int32_t mantissa = ~x;
-        int32_t exponent = (mantissa >> 4) & 7;
-        int32_t segment = exponent + 1;
-        mantissa &= 0x0f;
-
-        int32_t step = 4 << segment;
-
-        int32_t abs = (0x80l << exponent) + step * mantissa + step / 2 - 4 * 33;
-
-        *out++ = (x < 0x80) ? -abs : abs;
-    }
-}
-#endif
-
 class C2SoftG711DecFactory : public C2ComponentFactory {
 public:
     C2SoftG711DecFactory() : mHelper(std::static_pointer_cast<C2ReflectorHelper>(
diff --git a/media/codec2/components/g711/C2SoftG711Dec.h b/media/codec2/components/g711/C2SoftG711Dec.h
index 23e8ffc..f93840b 100644
--- a/media/codec2/components/g711/C2SoftG711Dec.h
+++ b/media/codec2/components/g711/C2SoftG711Dec.h
@@ -45,12 +45,6 @@
     std::shared_ptr<IntfImpl> mIntf;
     bool mSignalledOutputEos;
 
-#ifdef ALAW
-    void DecodeALaw(int16_t *out, const uint8_t *in, size_t inSize);
-#else
-    void DecodeMLaw(int16_t *out, const uint8_t *in, size_t inSize);
-#endif
-
     C2_DO_NOT_COPY(C2SoftG711Dec);
 };
 
diff --git a/media/codec2/components/gsm/C2SoftGsmDec.h b/media/codec2/components/gsm/C2SoftGsmDec.h
index 2b209fe..edd273b 100644
--- a/media/codec2/components/gsm/C2SoftGsmDec.h
+++ b/media/codec2/components/gsm/C2SoftGsmDec.h
@@ -19,10 +19,7 @@
 
 #include <SimpleC2Component.h>
 
-
-extern "C" {
-    #include "gsm.h"
-}
+#include "gsm.h"
 
 namespace android {
 
diff --git a/media/codec2/sfplugin/CCodec.cpp b/media/codec2/sfplugin/CCodec.cpp
index cc132de..5eaa167 100644
--- a/media/codec2/sfplugin/CCodec.cpp
+++ b/media/codec2/sfplugin/CCodec.cpp
@@ -1809,15 +1809,18 @@
                         // move all info into output-stream #0 domain
                         updates.emplace_back(C2Param::CopyAsStream(*info, true /* output */, stream));
                     }
-                    for (const C2ConstGraphicBlock &block : buf->data().graphicBlocks()) {
+
+                    const std::vector<C2ConstGraphicBlock> blocks = buf->data().graphicBlocks();
+                    // for now only do the first block
+                    if (!blocks.empty()) {
                         // ALOGV("got output buffer with crop %u,%u+%u,%u and size %u,%u",
                         //      block.crop().left, block.crop().top,
                         //      block.crop().width, block.crop().height,
                         //      block.width(), block.height());
+                        const C2ConstGraphicBlock &block = blocks[0];
                         updates.emplace_back(new C2StreamCropRectInfo::output(stream, block.crop()));
                         updates.emplace_back(new C2StreamPictureSizeInfo::output(
                                 stream, block.crop().width, block.crop().height));
-                        break; // for now only do the first block
                     }
                     ++stream;
                 }
@@ -1829,7 +1832,7 @@
                 // copy standard infos to graphic buffers if not already present (otherwise, we
                 // may overwrite the actual intermediate value with a final value)
                 stream = 0;
-                const static std::vector<C2Param::Index> stdGfxInfos = {
+                const static C2Param::Index stdGfxInfos[] = {
                     C2StreamRotationInfo::output::PARAM_TYPE,
                     C2StreamColorAspectsInfo::output::PARAM_TYPE,
                     C2StreamDataSpaceInfo::output::PARAM_TYPE,
diff --git a/media/codec2/vndk/util/C2InterfaceUtils.cpp b/media/codec2/vndk/util/C2InterfaceUtils.cpp
index 61ec911..0c1729b 100644
--- a/media/codec2/vndk/util/C2InterfaceUtils.cpp
+++ b/media/codec2/vndk/util/C2InterfaceUtils.cpp
@@ -216,9 +216,14 @@
     if (limit.contains(minMask) && contains(minMask)) {
         values[0] = minMask;
         // keep only flags that are covered by limit
-        std::remove_if(values.begin(), values.end(), [&limit, minMask](const C2Value::Primitive &v) -> bool {
-            T value = v.ref<ValueType>() | minMask;
-            return value == minMask || !limit.contains(value); });
+        values.erase(std::remove_if(values.begin(), values.end(),
+                                    [&limit, minMask](
+                                        const C2Value::Primitive &v) -> bool {
+                                      T value = v.ref<ValueType>() | minMask;
+                                      return value == minMask ||
+                                             !limit.contains(value);
+                                    }),
+                     values.end());
         // we also need to do it vice versa
         for (const C2Value::Primitive &v : _mValues) {
             T value = v.ref<ValueType>() | minMask;
@@ -264,24 +269,33 @@
 template<typename T>
 C2SupportedValueSet<T> C2SupportedValueSet<T>::limitedTo(const C2SupportedValueSet<T> &limit) const {
     std::vector<C2Value::Primitive> values = _mValues; // make a copy
-    std::remove_if(values.begin(), values.end(), [&limit](const C2Value::Primitive &v) -> bool {
-        return !limit.contains(v.ref<ValueType>()); });
+    values.erase(std::remove_if(values.begin(), values.end(),
+                                [&limit](const C2Value::Primitive &v) -> bool {
+                                  return !limit.contains(v.ref<ValueType>());
+                                }),
+                 values.end());
     return C2SupportedValueSet(std::move(values));
 }
 
 template<typename T>
 C2SupportedValueSet<T> C2SupportedValueSet<T>::limitedTo(const C2SupportedRange<T> &limit) const {
     std::vector<C2Value::Primitive> values = _mValues; // make a copy
-    std::remove_if(values.begin(), values.end(), [&limit](const C2Value::Primitive &v) -> bool {
-        return !limit.contains(v.ref<ValueType>()); });
+    values.erase(std::remove_if(values.begin(), values.end(),
+                                [&limit](const C2Value::Primitive &v) -> bool {
+                                  return !limit.contains(v.ref<ValueType>());
+                                }),
+                 values.end());
     return C2SupportedValueSet(std::move(values));
 }
 
 template<typename T>
 C2SupportedValueSet<T> C2SupportedValueSet<T>::limitedTo(const C2SupportedFlags<T> &limit) const {
     std::vector<C2Value::Primitive> values = _mValues; // make a copy
-    std::remove_if(values.begin(), values.end(), [&limit](const C2Value::Primitive &v) -> bool {
-        return !limit.contains(v.ref<ValueType>()); });
+    values.erase(std::remove_if(values.begin(), values.end(),
+                                [&limit](const C2Value::Primitive &v) -> bool {
+                                  return !limit.contains(v.ref<ValueType>());
+                                }),
+                 values.end());
     return C2SupportedValueSet(std::move(values));
 }
 
diff --git a/media/codecs/g711/decoder/Android.bp b/media/codecs/g711/decoder/Android.bp
new file mode 100644
index 0000000..377833f
--- /dev/null
+++ b/media/codecs/g711/decoder/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_library_static {
+    name: "codecs_g711dec",
+    vendor_available: true,
+    host_supported: true,
+
+    srcs: [
+        "g711DecAlaw.cpp",
+        "g711DecMlaw.cpp",
+    ],
+
+    export_include_dirs: ["."],
+
+    cflags: ["-Werror"],
+
+    sanitize: {
+        misc_undefined: [
+            "signed-integer-overflow",
+            "unsigned-integer-overflow",
+        ],
+        cfi: true,
+    },
+    apex_available: ["com.android.media.swcodec"],
+
+    target: {
+        darwin: {
+            enabled: false,
+        },
+    },
+}
diff --git a/media/codecs/g711/decoder/g711Dec.h b/media/codecs/g711/decoder/g711Dec.h
new file mode 100644
index 0000000..ca357a5
--- /dev/null
+++ b/media/codecs/g711/decoder/g711Dec.h
@@ -0,0 +1,41 @@
+/*
+ * 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 G711_DEC_H_
+#define G711_DEC_H_
+
+/**
+ * @file g711Dec.h
+ * @brief g711 Decoder API: DecodeALaw and DecodeMLaw
+ */
+
+/** Decodes input bytes of size inSize according to ALAW
+ *
+ * @param [in] out <tt>int16_t*</tt>: output buffer to be filled with decoded bytes.
+ * @param [in] in <tt>const uint8_t*</tt>: input buffer containing bytes to be decoded.
+ * @param [in] inSize <tt>size_t</tt>: size of the input buffer.
+ */
+void DecodeALaw(int16_t *out, const uint8_t *in, size_t inSize);
+
+/** Decodes input bytes of size inSize according to MLAW
+ *
+ * @param [in] out <tt>int16_t*</tt>: output buffer to be filled with decoded bytes.
+ * @param [in] in <tt>const uint8_t*</tt>: input buffer containing bytes to be decoded.
+ * @param [in] inSize <tt>size_t</tt>: size of the input buffer.
+ */
+void DecodeMLaw(int16_t *out, const uint8_t *in, size_t inSize);
+
+#endif  // G711_DECODER_H_
diff --git a/media/codecs/g711/decoder/g711DecAlaw.cpp b/media/codecs/g711/decoder/g711DecAlaw.cpp
new file mode 100644
index 0000000..e41a7b4
--- /dev/null
+++ b/media/codecs/g711/decoder/g711DecAlaw.cpp
@@ -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.
+ */
+
+#include <stddef.h>
+#include <stdint.h>
+
+void DecodeALaw(int16_t *out, const uint8_t *in, size_t inSize) {
+  if (out != nullptr && in != nullptr) {
+    while (inSize > 0) {
+      inSize--;
+      int32_t x = *in++;
+
+      int32_t ix = x ^ 0x55;
+      ix &= 0x7f;
+
+      int32_t iexp = ix >> 4;
+      int32_t mant = ix & 0x0f;
+
+      if (iexp > 0) {
+        mant += 16;
+      }
+
+      mant = (mant << 4) + 8;
+
+      if (iexp > 1) {
+        mant = mant << (iexp - 1);
+      }
+
+      *out++ = (x > 127) ? mant : -mant;
+    }
+  }
+}
diff --git a/media/codecs/g711/decoder/g711DecMlaw.cpp b/media/codecs/g711/decoder/g711DecMlaw.cpp
new file mode 100644
index 0000000..bb2caea
--- /dev/null
+++ b/media/codecs/g711/decoder/g711DecMlaw.cpp
@@ -0,0 +1,38 @@
+/*
+ * 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.
+ */
+
+#include <stddef.h>
+#include <stdint.h>
+
+void DecodeMLaw(int16_t *out, const uint8_t *in, size_t inSize) {
+  if (out != nullptr && in != nullptr) {
+    while (inSize > 0) {
+      inSize--;
+      int32_t x = *in++;
+
+      int32_t mantissa = ~x;
+      int32_t exponent = (mantissa >> 4) & 7;
+      int32_t segment = exponent + 1;
+      mantissa &= 0x0f;
+
+      int32_t step = 4 << segment;
+
+      int32_t abs = (0x80l << exponent) + step * mantissa + step / 2 - 4 * 33;
+
+      *out++ = (x < 0x80) ? -abs : abs;
+    }
+  }
+}
diff --git a/media/codecs/g711/fuzzer/Android.bp b/media/codecs/g711/fuzzer/Android.bp
new file mode 100644
index 0000000..1aee7f5
--- /dev/null
+++ b/media/codecs/g711/fuzzer/Android.bp
@@ -0,0 +1,44 @@
+/******************************************************************************
+ *
+ * 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_fuzz {
+    name: "g711alaw_dec_fuzzer",
+    host_supported: true,
+    srcs: [
+        "g711_dec_fuzzer.cpp",
+    ],
+    static_libs: [
+        "codecs_g711dec",
+    ],
+    cflags: [
+        "-DALAW",
+    ],
+}
+
+cc_fuzz {
+    name: "g711mlaw_dec_fuzzer",
+    host_supported: true,
+    srcs: [
+        "g711_dec_fuzzer.cpp",
+    ],
+    static_libs: [
+        "codecs_g711dec",
+    ],
+}
diff --git a/media/codecs/g711/fuzzer/README.md b/media/codecs/g711/fuzzer/README.md
new file mode 100644
index 0000000..0c1c36b
--- /dev/null
+++ b/media/codecs/g711/fuzzer/README.md
@@ -0,0 +1,49 @@
+# Fuzzer for libstagefright_g711dec decoder
+
+## Plugin Design Considerations
+The fuzzer plugin for G711 is designed based on the understanding of the
+codec and tries to achieve the following:
+
+##### Maximize code coverage
+G711 supports two types of decoding:
+1. DecodeALaw
+2. DecodeMLaw
+
+These two decoder API's are fuzzed separately using g711alaw_dec_fuzzer and
+g711mlaw_dec_fuzzer respectively.
+
+##### Maximize utilization of input data
+The plugin feeds the entire input data to the codec as expected by decoder API.
+
+## Build
+
+This describes steps to build g711alaw_dec_fuzzer and g711mlaw_dec_fuzzer binary.
+
+### Android
+
+#### Steps to build
+Build the fuzzer
+```
+  $ mm -j$(nproc) g711alaw_dec_fuzzer
+  $ mm -j$(nproc) g711mlaw_dec_fuzzer
+```
+
+#### Steps to run
+Create a directory CORPUS_DIR and copy some g711 files to that folder
+Push this directory to device.
+
+To run on device
+```
+  $ adb sync data
+  $ adb shell /data/fuzz/arm64/g711alaw_dec_fuzzer/g711alaw_dec_fuzzer CORPUS_DIR
+  $ adb shell /data/fuzz/arm64/g711mlaw_dec_fuzzer/g711mlaw_dec_fuzzer CORPUS_DIR
+```
+To run on host
+```
+  $ $ANDROID_HOST_OUT/fuzz/x86_64/g711alaw_dec_fuzzer/g711alaw_dec_fuzzer CORPUS_DIR
+  $ $ANDROID_HOST_OUT/fuzz/x86_64/g711mlaw_dec_fuzzer/g711mlaw_dec_fuzzer CORPUS_DIR
+```
+
+## References:
+ * http://llvm.org/docs/LibFuzzer.html
+ * https://github.com/google/oss-fuzz
diff --git a/media/codecs/g711/fuzzer/g711_dec_fuzzer.cpp b/media/codecs/g711/fuzzer/g711_dec_fuzzer.cpp
new file mode 100644
index 0000000..adfbcf5
--- /dev/null
+++ b/media/codecs/g711/fuzzer/g711_dec_fuzzer.cpp
@@ -0,0 +1,58 @@
+/******************************************************************************
+ *
+ * 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 <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include "g711Dec.h"
+
+class Codec {
+ public:
+  Codec() = default;
+  ~Codec() = default;
+  void decodeFrames(const uint8_t *data, size_t size);
+};
+
+void Codec::decodeFrames(const uint8_t *data, size_t size) {
+  size_t outputBufferSize = sizeof(int16_t) * size;
+  int16_t *out = new int16_t[outputBufferSize];
+  if (!out) {
+    return;
+  }
+#ifdef ALAW
+  DecodeALaw(out, data, size);
+#else
+  DecodeMLaw(out, data, size);
+#endif
+  delete[] out;
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+  if (size < 1) {
+    return 0;
+  }
+  Codec *codec = new Codec();
+  if (!codec) {
+    return 0;
+  }
+  codec->decodeFrames(data, size);
+  delete codec;
+  return 0;
+}
diff --git a/media/extractors/fuzzers/Android.bp b/media/extractors/fuzzers/Android.bp
new file mode 100644
index 0000000..5fb8155
--- /dev/null
+++ b/media/extractors/fuzzers/Android.bp
@@ -0,0 +1,83 @@
+/******************************************************************************
+ *
+ * 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_library {
+    name: "libextractorfuzzerbase",
+
+    srcs: [
+        "ExtractorFuzzerBase.cpp",
+    ],
+
+    local_include_dirs: [
+        "include",
+    ],
+
+    export_include_dirs: [
+        "include",
+    ],
+
+    static_libs: [
+        "liblog",
+        "libstagefright_foundation",
+        "libmedia",
+    ],
+
+    shared_libs: [
+        "libutils",
+        "libbinder",
+        "libmediandk",
+    ],
+
+    /* GETEXTRACTORDEF is not defined as extractor library is not linked in the
+     * base class. It will be included when the extractor fuzzer binary is
+     * generated.
+     */
+    allow_undefined_symbols: true,
+}
+
+cc_fuzz {
+    name: "mp4_extractor_fuzzer",
+
+    srcs: [
+        "mp4_extractor_fuzzer.cpp",
+    ],
+
+    include_dirs: [
+        "frameworks/av/media/extractors/mp4",
+    ],
+
+    static_libs: [
+        "liblog",
+        "libstagefright_foundation",
+        "libmedia",
+        "libextractorfuzzerbase",
+        "libstagefright_id3",
+        "libstagefright_esds",
+        "libmp4extractor",
+    ],
+
+    shared_libs: [
+        "libutils",
+        "libmediandk",
+        "libbinder",
+    ],
+
+    dictionary: "mp4_extractor_fuzzer.dict",
+}
diff --git a/media/extractors/fuzzers/ExtractorFuzzerBase.cpp b/media/extractors/fuzzers/ExtractorFuzzerBase.cpp
new file mode 100644
index 0000000..cbd6395
--- /dev/null
+++ b/media/extractors/fuzzers/ExtractorFuzzerBase.cpp
@@ -0,0 +1,118 @@
+/*
+ * 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 "ExtractorFuzzerBase"
+#include <utils/Log.h>
+
+#include "ExtractorFuzzerBase.h"
+
+using namespace android;
+
+bool ExtractorFuzzerBase::setDataSource(const uint8_t* data, size_t size) {
+  if ((!data) || (size == 0)) {
+    return false;
+  }
+  mBufferSource = new BufferSource(data, size);
+  mDataSource = reinterpret_cast<DataSource*>(mBufferSource.get());
+  if (!mDataSource) {
+    return false;
+  }
+  return true;
+}
+
+bool ExtractorFuzzerBase::getExtractorDef() {
+  float confidence;
+  void* meta = nullptr;
+  FreeMetaFunc freeMeta = nullptr;
+
+  ExtractorDef extractorDef = GETEXTRACTORDEF();
+  if (extractorDef.def_version == EXTRACTORDEF_VERSION_NDK_V1) {
+    extractorDef.u.v2.sniff(mDataSource->wrap(), &confidence, &meta, &freeMeta);
+  } else if (extractorDef.def_version == EXTRACTORDEF_VERSION_NDK_V2) {
+    extractorDef.u.v3.sniff(mDataSource->wrap(), &confidence, &meta, &freeMeta);
+  }
+
+  if (meta != nullptr && freeMeta != nullptr) {
+    freeMeta(meta);
+  }
+
+  return true;
+}
+
+bool ExtractorFuzzerBase::extractTracks() {
+  MediaBufferGroup* bufferGroup = new MediaBufferGroup();
+  if (!bufferGroup) {
+    return false;
+  }
+  for (size_t trackIndex = 0; trackIndex < mExtractor->countTracks(); ++trackIndex) {
+    MediaTrackHelper* track = mExtractor->getTrack(trackIndex);
+    if (!track) {
+      continue;
+    }
+    extractTrack(track, bufferGroup);
+    delete track;
+  }
+  delete bufferGroup;
+  return true;
+}
+
+void ExtractorFuzzerBase::extractTrack(MediaTrackHelper* track, MediaBufferGroup* bufferGroup) {
+  CMediaTrack* cTrack = wrap(track);
+  if (!cTrack) {
+    return;
+  }
+
+  media_status_t status = cTrack->start(track, bufferGroup->wrap());
+  if (status != AMEDIA_OK) {
+    free(cTrack);
+    return;
+  }
+
+  do {
+    MediaBufferHelper* buffer = nullptr;
+    status = track->read(&buffer);
+    if (buffer) {
+      buffer->release();
+    }
+  } while (status == AMEDIA_OK);
+
+  cTrack->stop(track);
+  free(cTrack);
+}
+
+bool ExtractorFuzzerBase::getTracksMetadata() {
+  AMediaFormat* format = AMediaFormat_new();
+  uint32_t flags = MediaExtractorPluginHelper::kIncludeExtensiveMetaData;
+
+  for (size_t trackIndex = 0; trackIndex < mExtractor->countTracks(); ++trackIndex) {
+    mExtractor->getTrackMetaData(format, trackIndex, flags);
+  }
+
+  AMediaFormat_delete(format);
+  return true;
+}
+
+bool ExtractorFuzzerBase::getMetadata() {
+  AMediaFormat* format = AMediaFormat_new();
+  mExtractor->getMetaData(format);
+  AMediaFormat_delete(format);
+  return true;
+}
+
+void ExtractorFuzzerBase::setDataSourceFlags(uint32_t flags) {
+  mBufferSource->setFlags(flags);
+}
diff --git a/media/extractors/fuzzers/README.md b/media/extractors/fuzzers/README.md
new file mode 100644
index 0000000..a6c17c0
--- /dev/null
+++ b/media/extractors/fuzzers/README.md
@@ -0,0 +1,54 @@
+# Fuzzer for extractors
+
+## Table of contents
+1. [libextractorfuzzerbase](#ExtractorFuzzerBase)
+2. [libmp4extractor](#mp4ExtractorFuzzer)
+
+# <a name="ExtractorFuzzerBase"></a> Fuzzer for libextractorfuzzerbase
+All the extractors have a common API - creating a data source, extraction
+of all the tracks, etc. These common APIs have been abstracted in a base class
+called `ExtractorFuzzerBase` to ensure code is reused between fuzzer plugins.
+
+Additionally, `ExtractorFuzzerBase` also has support for memory based buffer
+`BufferSource` since the fuzzing engine feeds data using memory buffers and
+usage of standard data source objects like FileSource, HTTPSource, etc. is
+not feasible.
+
+# <a name="mp4ExtractorFuzzer"></a> Fuzzer for libmp4extractor
+
+## Plugin Design Considerations
+The fuzzer plugin for MP4 extractor uses the `ExtractorFuzzerBase` class and
+implements only the `createExtractor` to create the MP4 extractor class.
+
+##### Maximize code coverage
+Dict file (dictionary file) is created for MP4 to ensure that the required MP4
+atoms are present in every input file that goes to the fuzzer.
+This ensures that larger code gets covered as a range of MP4 atoms will be
+present in the input data.
+
+
+## Build
+
+This describes steps to build mp4_extractor_fuzzer binary.
+
+### Android
+
+#### Steps to build
+Build the fuzzer
+```
+  $ mm -j$(nproc) mp4_extractor_fuzzer
+```
+
+#### Steps to run
+Create a directory CORPUS_DIR and copy some MP4 files to that folder
+Push this directory to device.
+
+To run on device
+```
+  $ adb sync data
+  $ adb shell /data/fuzz/arm64/mp4_extractor_fuzzer/mp4_extractor_fuzzer CORPUS_DIR
+```
+
+## References:
+ * http://llvm.org/docs/LibFuzzer.html
+ * https://github.com/google/oss-fuzz
diff --git a/media/extractors/fuzzers/include/ExtractorFuzzerBase.h b/media/extractors/fuzzers/include/ExtractorFuzzerBase.h
new file mode 100644
index 0000000..abf362b
--- /dev/null
+++ b/media/extractors/fuzzers/include/ExtractorFuzzerBase.h
@@ -0,0 +1,130 @@
+/******************************************************************************
+ *
+ * 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 __EXTRACTOR_FUZZER_BASE_H__
+#define __EXTRACTOR_FUZZER_BASE_H__
+
+#include <media/DataSource.h>
+#include <media/MediaExtractorPluginHelper.h>
+#include <media/stagefright/MediaBufferGroup.h>
+
+extern "C" {
+android::ExtractorDef GETEXTRACTORDEF();
+}
+
+namespace android {
+
+class ExtractorFuzzerBase {
+ public:
+  ExtractorFuzzerBase() = default;
+  virtual ~ExtractorFuzzerBase() {
+    if (mExtractor) {
+      delete mExtractor;
+      mExtractor = nullptr;
+    }
+    if (mBufferSource) {
+      mBufferSource.clear();
+      mBufferSource = nullptr;
+    }
+  }
+
+  /** Function to create the media extractor component.
+    * To be implemented by the derived class.
+    */
+  virtual bool createExtractor() = 0;
+
+  /** Parent class functions to be reused by derived class.
+    * These are common for all media extractor components.
+    */
+  bool setDataSource(const uint8_t* data, size_t size);
+
+  bool getExtractorDef();
+
+  bool extractTracks();
+
+  bool getMetadata();
+
+  bool getTracksMetadata();
+
+  void setDataSourceFlags(uint32_t flags);
+
+ protected:
+  class BufferSource : public DataSource {
+   public:
+    BufferSource(const uint8_t* data, size_t length) : mData(data), mLength(length) {}
+    virtual ~BufferSource() { mData = nullptr; }
+
+    void setFlags(uint32_t flags) { mFlags = flags; }
+
+    uint32_t flags() { return mFlags; }
+
+    status_t initCheck() const { return mData != nullptr ? OK : NO_INIT; }
+
+    ssize_t readAt(off64_t offset, void* data, size_t size) {
+      if (!mData) {
+        return NO_INIT;
+      }
+
+      Mutex::Autolock autoLock(mLock);
+      if ((offset >= static_cast<off64_t>(mLength)) || (offset < 0)) {
+        return 0;  // read beyond bounds.
+      }
+      size_t numAvailable = mLength - static_cast<size_t>(offset);
+      if (size > numAvailable) {
+        size = numAvailable;
+      }
+      return readAt_l(offset, data, size);
+    }
+
+    status_t getSize(off64_t* size) {
+      if (!mData) {
+        return NO_INIT;
+      }
+
+      Mutex::Autolock autoLock(mLock);
+      *size = static_cast<off64_t>(mLength);
+      return OK;
+    }
+
+   protected:
+    ssize_t readAt_l(off64_t offset, void* data, size_t size) {
+      void* result = memcpy(data, mData + offset, size);
+      return result != nullptr ? size : 0;
+    }
+
+    const uint8_t* mData = nullptr;
+    size_t mLength = 0;
+    Mutex mLock;
+    uint32_t mFlags = 0;
+
+   private:
+    DISALLOW_EVIL_CONSTRUCTORS(BufferSource);
+  };
+
+  sp<BufferSource> mBufferSource;
+  DataSource* mDataSource = nullptr;
+  MediaExtractorPluginHelper* mExtractor = nullptr;
+
+  virtual void extractTrack(MediaTrackHelper* track, MediaBufferGroup* bufferGroup);
+};
+
+}  // namespace android
+
+#endif  // __EXTRACTOR_FUZZER_BASE_H__
diff --git a/media/extractors/fuzzers/mp4_extractor_fuzzer.cpp b/media/extractors/fuzzers/mp4_extractor_fuzzer.cpp
new file mode 100644
index 0000000..d2cc133
--- /dev/null
+++ b/media/extractors/fuzzers/mp4_extractor_fuzzer.cpp
@@ -0,0 +1,64 @@
+/******************************************************************************
+ *
+ * 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 "ExtractorFuzzerBase.h"
+
+#include "MPEG4Extractor.h"
+#include "SampleTable.h"
+
+using namespace android;
+
+class MP4Extractor : public ExtractorFuzzerBase {
+ public:
+  MP4Extractor() = default;
+  ~MP4Extractor() = default;
+
+  bool createExtractor();
+};
+
+bool MP4Extractor::createExtractor() {
+  mExtractor = new MPEG4Extractor(new DataSourceHelper(mDataSource->wrap()));
+  if (!mExtractor) {
+    return false;
+  }
+  mExtractor->name();
+  setDataSourceFlags(DataSourceBase::kWantsPrefetching | DataSourceBase::kIsCachingDataSource);
+  return true;
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+  if ((!data) || (size == 0)) {
+    return 0;
+  }
+  MP4Extractor* extractor = new MP4Extractor();
+  if (!extractor) {
+    return 0;
+  }
+  if (extractor->setDataSource(data, size)) {
+    if (extractor->createExtractor()) {
+      extractor->getExtractorDef();
+      extractor->getMetadata();
+      extractor->extractTracks();
+      extractor->getTracksMetadata();
+    }
+  }
+  delete extractor;
+  return 0;
+}
diff --git a/media/extractors/fuzzers/mp4_extractor_fuzzer.dict b/media/extractors/fuzzers/mp4_extractor_fuzzer.dict
new file mode 100644
index 0000000..42a86f3
--- /dev/null
+++ b/media/extractors/fuzzers/mp4_extractor_fuzzer.dict
@@ -0,0 +1,248 @@
+# MP4 Atoms/Boxes
+kw1="ftyp"
+kw2="free"
+kw3="mdat"
+kw4="moov"
+kw5="mvhd"
+kw6="trak"
+kw7="tkhd"
+kw8="edts"
+kw9="elst"
+kw10="mdia"
+kw11="mdhd"
+kw12="hdlr"
+kw13="minf"
+kw14="vmhd"
+kw15="dinf"
+kw16="dref"
+kw17="url "
+kw18="stbl"
+kw19="stsd"
+kw20="avc1"
+kw21="avcC"
+kw22="stts"
+kw23="stss"
+kw24="ctts"
+kw25="stsc"
+kw26="stsz"
+kw27="stco"
+kw28="mp4a"
+kw29="esds"
+kw30="udta"
+kw31="meta"
+kw32="ilst"
+kw33="samr"
+kw34="sawb"
+kw35="ec-3"
+kw36="mp4v"
+kw37="s263"
+kw38="h263"
+kw39="H263"
+kw40="avc1"
+kw41="hvc1"
+kw42="hev1"
+kw43="ac-4"
+kw44="Opus"
+kw45="twos"
+kw46="sowt"
+kw47="alac"
+kw48="fLaC"
+kw49="av01"
+kw50=".mp3"
+kw51="keys"
+kw52="cprt"
+kw53="covr"
+kw54="mvex"
+kw55="moof"
+kw56="traf"
+kw57="mfra"
+kw58="sinf"
+kw59="schi"
+kw60="wave"
+kw61="schm"
+kw62="cbc1"
+kw63="cbcs"
+kw64="cenc"
+kw65="cens"
+kw66="frma"
+kw67="tenc"
+kw68="tref"
+kw69="thmb"
+kw70="pssh"
+kw71="mett"
+kw72="enca"
+kw73="encv"
+kw74="co64"
+kw75="stz2"
+kw76="\251xyz"
+kw77="btrt"
+kw78="hvcC"
+kw79="av1C"
+kw80="d263"
+kw81="iloc"
+kw82="iinf"
+kw83="iprp"
+kw84="pitm"
+kw85="idat"
+kw86="iref"
+kw87="ipro"
+kw88="mean"
+kw89="name"
+kw90="data"
+kw91="mehd"
+kw92="text"
+kw93="sbtl"
+kw94="trex"
+kw95="tx3g"
+kw96="colr"
+kw97="titl"
+kw98="perf"
+kw99="auth"
+kw100="gnre"
+kw101="albm"
+kw102="yrrc"
+kw103="ID32"
+kw104="----"
+kw105="sidx"
+kw106="ac-3"
+kw107="qt  "
+kw108="mif1"
+kw109="heic"
+kw110="dac4"
+kw111="dec3"
+kw112="dac3"
+kw113="\251alb"
+kw114="\251ART"
+kw115="aART"
+kw116="\251day"
+kw117="\251nam"
+kw118="\251wrt"
+kw119="\251gen"
+kw120="cpil"
+kw121="trkn"
+kw122="disk"
+kw123="nclx"
+kw124="nclc"
+kw125="tfhd"
+kw126="trun"
+kw127="saiz"
+kw128="saio"
+kw129="senc"
+kw130="isom"
+kw131="iso2"
+kw132="3gp4"
+kw133="mp41"
+kw134="mp42"
+kw135="dash"
+kw136="nvr1"
+kw137="MSNV"
+kw138="wmf "
+kw139="3g2a"
+kw140="3g2b"
+kw141="msf1"
+kw142="hevc"
+kw143="pdin"
+kw144="trgr"
+kw145="smhd"
+kw146="hmhd"
+kw147="nmhd"
+kw148="cslg"
+kw149="stsh"
+kw150="padb"
+kw151="stdp"
+kw152="sdtp"
+kw153="sbgp"
+kw154="sgpd"
+kw155="subs"
+kw156="leva"
+kw157="mfhd"
+kw158="tfdt"
+kw159="tfra"
+kw160="mfro"
+kw161="skip"
+kw162="tsel"
+kw163="strk"
+kw164="stri"
+kw165="strd"
+kw166="xml "
+kw167="bxml"
+kw168="fiin"
+kw169="paen"
+kw170="fire"
+kw171="fpar"
+kw172="fecr"
+kw173="segr"
+kw174="gitn"
+kw175="meco"
+kw176="mere"
+kw177="styp"
+kw178="ssix"
+kw179="prft"
+kw180="hint"
+kw181="cdsc"
+kw182="hind"
+kw183="vdep"
+kw184="vplx"
+kw185="msrc"
+kw186="urn "
+kw187="enct"
+kw188="encs"
+kw189="rinf"
+kw190="srpp"
+kw191="stsg"
+kw192="stvi"
+kw193="tims"
+kw194="tsro"
+kw195="snro"
+kw196="rtp "
+kw197="srtp"
+kw198="rtpo"
+kw199="hnti"
+kw200="sdp "
+kw201="trpy"
+kw202="nump"
+kw203="tpyl"
+kw204="totl"
+kw205="npck"
+kw206="tpay"
+kw207="maxr"
+kw208="dmed"
+kw209="dimm"
+kw210="drep"
+kw211="tmin"
+kw212="tmax"
+kw213="pmax"
+kw214="dmax"
+kw215="payt"
+kw216="fdp "
+kw217="fdsa"
+kw218="fdpa"
+kw219="extr"
+kw220="feci"
+kw221="rm2t"
+kw222="sm2t"
+kw223="tPAT"
+kw224="tPMT"
+kw225="tOD "
+kw226="tsti"
+kw227="istm"
+kw228="pm2t"
+kw229="rrtp"
+kw230="rssr"
+kw231="rscr"
+kw232="rsrp"
+kw233="rssr"
+kw234="ccid"
+kw235="sroc"
+kw236="prtp"
+kw237="roll"
+kw238="rash"
+kw239="alst"
+kw240="rap "
+kw241="tele"
+kw242="mp71"
+kw243="iso3"
+kw244="iso4"
+kw245="iso5"
+kw246="resv"
+kw247="iso6"
diff --git a/media/extractors/mkv/MatroskaExtractor.cpp b/media/extractors/mkv/MatroskaExtractor.cpp
index 044c4d0..c9004ec 100644
--- a/media/extractors/mkv/MatroskaExtractor.cpp
+++ b/media/extractors/mkv/MatroskaExtractor.cpp
@@ -1879,13 +1879,12 @@
 
     for(size_t i = 0; i < track->GetContentEncodingCount(); i++) {
         const mkvparser::ContentEncoding *encoding = track->GetContentEncodingByIndex(i);
-        for(size_t j = 0; j < encoding->GetEncryptionCount(); j++) {
+        if (encoding->GetEncryptionCount() > 0) {
             const mkvparser::ContentEncoding::ContentEncryption *encryption;
-            encryption = encoding->GetEncryptionByIndex(j);
+            encryption = encoding->GetEncryptionByIndex(0);
             AMediaFormat_setBuffer(trackInfo->mMeta,
                     AMEDIAFORMAT_KEY_CRYPTO_KEY, encryption->key_id, encryption->key_id_len);
             trackInfo->mEncrypted = true;
-            break;
         }
 
         for(size_t j = 0; j < encoding->GetCompressionCount(); j++) {
diff --git a/media/extractors/tests/ExtractorUnitTest.cpp b/media/extractors/tests/ExtractorUnitTest.cpp
index 518166e..f18a7dc 100644
--- a/media/extractors/tests/ExtractorUnitTest.cpp
+++ b/media/extractors/tests/ExtractorUnitTest.cpp
@@ -20,8 +20,10 @@
 
 #include <datasource/FileSource.h>
 #include <media/stagefright/MediaBufferGroup.h>
+#include <media/stagefright/MediaCodecConstants.h>
 #include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MetaDataUtils.h>
+#include <media/stagefright/foundation/OpusHeader.h>
 
 #include "aac/AACExtractor.h"
 #include "amr/AMRExtractor.h"
@@ -43,11 +45,45 @@
 #define OUTPUT_DUMP_FILE "/data/local/tmp/extractorOutput"
 
 constexpr int32_t kMaxCount = 10;
-constexpr int32_t kOpusSeekPreRollUs = 80000;  // 80 ms;
+constexpr int32_t kAudioDefaultSampleDuration = 20000;                       // 20ms
+constexpr int32_t kRandomSeekToleranceUs = 2 * kAudioDefaultSampleDuration;  // 40 ms;
+constexpr int32_t kRandomSeed = 700;
+constexpr int32_t kUndefined = -1;
+
+// LookUpTable of clips and metadata for component testing
+static const struct InputData {
+    string mime;
+    string inputFile;
+    int32_t firstParam;
+    int32_t secondParam;
+    int32_t profile;
+    int32_t frameRate;
+} kInputData[] = {
+        {MEDIA_MIMETYPE_AUDIO_AAC, "test_mono_44100Hz_aac.aac", 44100, 1, AACObjectLC, kUndefined},
+        {MEDIA_MIMETYPE_AUDIO_AMR_NB, "bbb_mono_8kHz_amrnb.amr", 8000, 1, kUndefined, kUndefined},
+        {MEDIA_MIMETYPE_AUDIO_AMR_WB, "bbb_mono_16kHz_amrwb.amr", 16000, 1, kUndefined, kUndefined},
+        {MEDIA_MIMETYPE_AUDIO_VORBIS, "bbb_stereo_48kHz_vorbis.ogg", 48000, 2, kUndefined,
+         kUndefined},
+        {MEDIA_MIMETYPE_AUDIO_MSGSM, "test_mono_8kHz_gsm.wav", 8000, 1, kUndefined, kUndefined},
+        {MEDIA_MIMETYPE_AUDIO_RAW, "bbb_stereo_48kHz_flac.flac", 48000, 2, kUndefined, kUndefined},
+        {MEDIA_MIMETYPE_AUDIO_OPUS, "test_stereo_48kHz_opus.opus", 48000, 2, kUndefined,
+         kUndefined},
+        {MEDIA_MIMETYPE_AUDIO_MPEG, "bbb_stereo_48kHz_mp3.mp3", 48000, 2, kUndefined, kUndefined},
+        {MEDIA_MIMETYPE_AUDIO_RAW, "midi_a.mid", 22050, 2, kUndefined, kUndefined},
+        {MEDIA_MIMETYPE_VIDEO_MPEG2, "bbb_cif_768kbps_30fps_mpeg2.ts", 352, 288, MPEG2ProfileMain,
+         30},
+        {MEDIA_MIMETYPE_VIDEO_MPEG4, "bbb_cif_768kbps_30fps_mpeg4.mkv", 352, 288,
+         MPEG4ProfileSimple, 30},
+        // Test (b/151677264) for MP4 extractor
+        {MEDIA_MIMETYPE_VIDEO_HEVC, "crowd_508x240_25fps_hevc.mp4", 508, 240, HEVCProfileMain,
+         25},
+        {MEDIA_MIMETYPE_VIDEO_VP9, "bbb_340x280_30fps_vp9.webm", 340, 280, VP9Profile0, 30},
+        {MEDIA_MIMETYPE_VIDEO_MPEG2, "swirl_144x136_mpeg2.mpg", 144, 136, MPEG2ProfileMain, 12},
+};
 
 static ExtractorUnitTestEnvironment *gEnv = nullptr;
 
-class ExtractorUnitTest : public ::testing::TestWithParam<pair<string, string>> {
+class ExtractorUnitTest {
   public:
     ExtractorUnitTest() : mInputFp(nullptr), mDataSource(nullptr), mExtractor(nullptr) {}
 
@@ -66,7 +102,7 @@
         }
     }
 
-    virtual void SetUp() override {
+    void setupExtractor(string writerFormat) {
         mExtractorName = unknown_comp;
         mDisableTest = false;
 
@@ -75,7 +111,6 @@
                 {"wav", WAV},     {"mkv", MKV},         {"flac", FLAC},      {"midi", MIDI},
                 {"mpeg4", MPEG4}, {"mpeg2ts", MPEG2TS}, {"mpeg2ps", MPEG2PS}};
         // Find the component type
-        string writerFormat = GetParam().first;
         if (mapExtractor.find(writerFormat) != mapExtractor.end()) {
             mExtractorName = mapExtractor.at(writerFormat);
         }
@@ -112,6 +147,30 @@
     MediaExtractorPluginHelper *mExtractor;
 };
 
+class ExtractorFunctionalityTest : public ExtractorUnitTest,
+                                   public ::testing::TestWithParam<pair<string, string>> {
+  public:
+    virtual void SetUp() override { setupExtractor(GetParam().first); }
+};
+
+class ConfigParamTest : public ExtractorUnitTest,
+                        public ::testing::TestWithParam<pair<string, int32_t>> {
+  public:
+    virtual void SetUp() override { setupExtractor(GetParam().first); }
+
+    struct configFormat {
+        string mime;
+        int32_t width;
+        int32_t height;
+        int32_t sampleRate;
+        int32_t channelCount;
+        int32_t profile;
+        int32_t frameRate;
+    };
+
+    void getFileProperties(int32_t inputIdx, string &inputFile, configFormat &configParam);
+};
+
 int32_t ExtractorUnitTest::setDataSource(string inputFileName) {
     mInputFp = fopen(inputFileName.c_str(), "rb");
     if (!mInputFp) {
@@ -168,6 +227,68 @@
     return 0;
 }
 
+void ConfigParamTest::getFileProperties(int32_t inputIdx, string &inputFile,
+                                        configFormat &configParam) {
+    if (inputIdx >= sizeof(kInputData) / sizeof(kInputData[0])) {
+        return;
+    }
+    inputFile += kInputData[inputIdx].inputFile;
+    configParam.mime = kInputData[inputIdx].mime;
+    size_t found = configParam.mime.find("audio/");
+    // Check if 'audio/' is present in the begininig of the mime type
+    if (found == 0) {
+        configParam.sampleRate = kInputData[inputIdx].firstParam;
+        configParam.channelCount = kInputData[inputIdx].secondParam;
+    } else {
+        configParam.width = kInputData[inputIdx].firstParam;
+        configParam.height = kInputData[inputIdx].secondParam;
+    }
+    configParam.profile = kInputData[inputIdx].profile;
+    configParam.frameRate = kInputData[inputIdx].frameRate;
+    return;
+}
+
+void randomSeekTest(MediaTrackHelper *track, int64_t clipDuration) {
+    int32_t status = 0;
+    int32_t seekCount = 0;
+    bool hasTimestamp = false;
+    vector<int64_t> seekToTimeStamp;
+    string seekPtsString;
+
+    srand(kRandomSeed);
+    while (seekCount < kMaxCount) {
+        int64_t timeStamp = ((double)rand() / RAND_MAX) * clipDuration;
+        seekToTimeStamp.push_back(timeStamp);
+        seekPtsString.append(to_string(timeStamp));
+        seekPtsString.append(", ");
+        seekCount++;
+    }
+
+    for (int64_t seekPts : seekToTimeStamp) {
+        MediaTrackHelper::ReadOptions *options = new MediaTrackHelper::ReadOptions(
+                CMediaTrackReadOptions::SEEK_CLOSEST | CMediaTrackReadOptions::SEEK, seekPts);
+        ASSERT_NE(options, nullptr) << "Cannot create read option";
+
+        MediaBufferHelper *buffer = nullptr;
+        status = track->read(&buffer, options);
+        if (buffer) {
+            AMediaFormat *metaData = buffer->meta_data();
+            int64_t timeStamp = 0;
+            hasTimestamp = AMediaFormat_getInt64(metaData, AMEDIAFORMAT_KEY_TIME_US, &timeStamp);
+            ASSERT_TRUE(hasTimestamp) << "Extractor didn't set timestamp for the given sample";
+
+            buffer->release();
+            EXPECT_LE(abs(timeStamp - seekPts), kRandomSeekToleranceUs)
+                    << "Seek unsuccessful. Expected timestamp range ["
+                    << seekPts - kRandomSeekToleranceUs << ", " << seekPts + kRandomSeekToleranceUs
+                    << "] "
+                    << "received " << timeStamp << ", list of input seek timestamps ["
+                    << seekPtsString << "]";
+        }
+        delete options;
+    }
+}
+
 void getSeekablePoints(vector<int64_t> &seekablePoints, MediaTrackHelper *track) {
     int32_t status = 0;
     if (!seekablePoints.empty()) {
@@ -190,7 +311,7 @@
     }
 }
 
-TEST_P(ExtractorUnitTest, CreateExtractorTest) {
+TEST_P(ExtractorFunctionalityTest, CreateExtractorTest) {
     if (mDisableTest) return;
 
     ALOGV("Checks if a valid extractor is created for a given input file");
@@ -212,7 +333,7 @@
     AMediaFormat_delete(format);
 }
 
-TEST_P(ExtractorUnitTest, ExtractorTest) {
+TEST_P(ExtractorFunctionalityTest, ExtractorTest) {
     if (mDisableTest) return;
 
     ALOGV("Validates %s Extractor for a given input file", GetParam().first.c_str());
@@ -262,7 +383,7 @@
     }
 }
 
-TEST_P(ExtractorUnitTest, MetaDataComparisonTest) {
+TEST_P(ExtractorFunctionalityTest, MetaDataComparisonTest) {
     if (mDisableTest) return;
 
     ALOGV("Validates Extractor's meta data for a given input file");
@@ -337,7 +458,7 @@
     AMediaFormat_delete(extractorFormat);
 }
 
-TEST_P(ExtractorUnitTest, MultipleStartStopTest) {
+TEST_P(ExtractorFunctionalityTest, MultipleStartStopTest) {
     if (mDisableTest) return;
 
     ALOGV("Test %s extractor for multiple start and stop calls", GetParam().first.c_str());
@@ -379,10 +500,8 @@
     }
 }
 
-TEST_P(ExtractorUnitTest, SeekTest) {
-    // Both Flac and Wav extractor can give samples from any pts and mark the given sample as
-    // sync frame. So, this seek test is not applicable to FLAC and WAV extractors
-    if (mDisableTest || mExtractorName == FLAC || mExtractorName == WAV) return;
+TEST_P(ExtractorFunctionalityTest, SeekTest) {
+    if (mDisableTest) return;
 
     ALOGV("Validates %s Extractor behaviour for different seek modes", GetParam().first.c_str());
     string inputFileName = gEnv->getRes() + GetParam().second;
@@ -415,6 +534,32 @@
         MediaBufferGroup *bufferGroup = new MediaBufferGroup();
         status = cTrack->start(track, bufferGroup->wrap());
         ASSERT_EQ(OK, (media_status_t)status) << "Failed to start the track";
+
+        // For Flac, Wav and Midi extractor, all samples are seek points.
+        // We cannot create list of all seekable points for these.
+        // This means that if we pass a seekToTimeStamp between two seek points, we may
+        // end up getting the timestamp of next sample as a seekable timestamp.
+        // This timestamp may/may not be a part of the seekable point vector thereby failing the
+        // test. So we test these extractors using random seek test.
+        if (mExtractorName == FLAC || mExtractorName == WAV || mExtractorName == MIDI) {
+            AMediaFormat *trackMeta = AMediaFormat_new();
+            ASSERT_NE(trackMeta, nullptr) << "AMediaFormat_new returned null AMediaformat";
+
+            status = mExtractor->getTrackMetaData(trackMeta, idx, 1);
+            ASSERT_EQ(OK, (media_status_t)status) << "Failed to get trackMetaData";
+
+            int64_t clipDuration = 0;
+            AMediaFormat_getInt64(trackMeta, AMEDIAFORMAT_KEY_DURATION, &clipDuration);
+            ASSERT_GT(clipDuration, 0) << "Invalid clip duration ";
+            randomSeekTest(track, clipDuration);
+            AMediaFormat_delete(trackMeta);
+            continue;
+        }
+        // Request seekable points for remaining extractors which will be used to validate the seek
+        // accuracy for the extractors. Depending on SEEK Mode, we expect the extractors to return
+        // the expected sync frame. We don't prefer random seek test for these extractors because
+        // they aren't expected to seek to random samples. MP4 for instance can seek to
+        // next/previous sync frames but not to samples between two sync frames.
         getSeekablePoints(seekablePoints, track);
         ASSERT_GT(seekablePoints.size(), 0)
                 << "Failed to get seekable points for " << GetParam().first << " extractor";
@@ -425,9 +570,31 @@
         ASSERT_EQ(OK, (media_status_t)status) << "Failed to get track meta data";
 
         bool isOpus = false;
+        int64_t opusSeekPreRollUs = 0;
         const char *mime;
         AMediaFormat_getString(trackFormat, AMEDIAFORMAT_KEY_MIME, &mime);
-        if (!strcmp(mime, "audio/opus")) isOpus = true;
+        if (!strcmp(mime, "audio/opus")) {
+            isOpus = true;
+            void *seekPreRollBuf = nullptr;
+            size_t size = 0;
+            if (!AMediaFormat_getBuffer(trackFormat, "csd-2", &seekPreRollBuf, &size)) {
+                size_t opusHeadSize = 0;
+                size_t codecDelayBufSize = 0;
+                size_t seekPreRollBufSize = 0;
+                void *csdBuffer = nullptr;
+                void *opusHeadBuf = nullptr;
+                void *codecDelayBuf = nullptr;
+                AMediaFormat_getBuffer(trackFormat, "csd-0", &csdBuffer, &size);
+                ASSERT_NE(csdBuffer, nullptr);
+
+                GetOpusHeaderBuffers((uint8_t *)csdBuffer, size, &opusHeadBuf, &opusHeadSize,
+                                     &codecDelayBuf, &codecDelayBufSize, &seekPreRollBuf,
+                                     &seekPreRollBufSize);
+            }
+            ASSERT_NE(seekPreRollBuf, nullptr)
+                    << "Invalid track format. SeekPreRoll info missing for Opus file";
+            opusSeekPreRollUs = *((int64_t *)seekPreRollBuf);
+        }
         AMediaFormat_delete(trackFormat);
 
         int32_t seekIdx = 0;
@@ -448,7 +615,7 @@
                 // extractor is calculated based on (seekPts - seekPreRollUs).
                 // So we add the preRoll value to the timeStamp we want to seek to.
                 if (isOpus) {
-                    seekToTimeStamp += kOpusSeekPreRollUs;
+                    seekToTimeStamp += opusSeekPreRollUs;
                 }
 
                 MediaTrackHelper::ReadOptions *options = new MediaTrackHelper::ReadOptions(
@@ -496,9 +663,94 @@
     seekablePoints.clear();
 }
 
-// TODO: (b/145332185)
-// Add MIDI inputs
-INSTANTIATE_TEST_SUITE_P(ExtractorUnitTestAll, ExtractorUnitTest,
+// This test validates config params for a given input file.
+// For this test we only take single track files since the focus of this test is
+// to validate the file properties reported by Extractor and not multi-track behavior
+TEST_P(ConfigParamTest, ConfigParamValidation) {
+    if (mDisableTest) return;
+
+    ALOGV("Validates %s Extractor for input's file properties", GetParam().first.c_str());
+    string inputFileName = gEnv->getRes();
+    int32_t inputFileIdx = GetParam().second;
+    configFormat configParam;
+    getFileProperties(inputFileIdx, inputFileName, configParam);
+
+    int32_t status = setDataSource(inputFileName);
+    ASSERT_EQ(status, 0) << "SetDataSource failed for " << GetParam().first << "extractor";
+
+    status = createExtractor();
+    ASSERT_EQ(status, 0) << "Extractor creation failed for " << GetParam().first << "extractor";
+
+    int32_t numTracks = mExtractor->countTracks();
+    ASSERT_GT(numTracks, 0) << "Extractor didn't find any track for the given clip";
+
+    MediaTrackHelper *track = mExtractor->getTrack(0);
+    ASSERT_NE(track, nullptr) << "Failed to get track for index 0";
+
+    AMediaFormat *trackFormat = AMediaFormat_new();
+    ASSERT_NE(trackFormat, nullptr) << "AMediaFormat_new returned null format";
+
+    status = track->getFormat(trackFormat);
+    ASSERT_EQ(OK, (media_status_t)status) << "Failed to get track meta data";
+
+    const char *trackMime;
+    bool valueFound = AMediaFormat_getString(trackFormat, AMEDIAFORMAT_KEY_MIME, &trackMime);
+    ASSERT_TRUE(valueFound) << "Mime type not set by extractor";
+    ASSERT_STREQ(configParam.mime.c_str(), trackMime) << "Invalid track format";
+
+    if (!strncmp(trackMime, "audio/", 6)) {
+        int32_t trackSampleRate, trackChannelCount;
+        ASSERT_TRUE(AMediaFormat_getInt32(trackFormat, AMEDIAFORMAT_KEY_CHANNEL_COUNT,
+                                          &trackChannelCount));
+        ASSERT_TRUE(
+                AMediaFormat_getInt32(trackFormat, AMEDIAFORMAT_KEY_SAMPLE_RATE, &trackSampleRate));
+        ASSERT_EQ(configParam.sampleRate, trackSampleRate) << "SampleRate not as expected";
+        ASSERT_EQ(configParam.channelCount, trackChannelCount) << "ChannelCount not as expected";
+    } else {
+        int32_t trackWidth, trackHeight;
+        ASSERT_TRUE(AMediaFormat_getInt32(trackFormat, AMEDIAFORMAT_KEY_WIDTH, &trackWidth));
+        ASSERT_TRUE(AMediaFormat_getInt32(trackFormat, AMEDIAFORMAT_KEY_HEIGHT, &trackHeight));
+        ASSERT_EQ(configParam.width, trackWidth) << "Width not as expected";
+        ASSERT_EQ(configParam.height, trackHeight) << "Height not as expected";
+
+        if (configParam.frameRate != kUndefined) {
+            int32_t frameRate;
+            ASSERT_TRUE(
+                    AMediaFormat_getInt32(trackFormat, AMEDIAFORMAT_KEY_FRAME_RATE, &frameRate));
+            ASSERT_EQ(configParam.frameRate, frameRate) << "frameRate not as expected";
+        }
+    }
+    // validate the profile for the input clip
+    int32_t profile;
+    if (configParam.profile != kUndefined) {
+        if (AMediaFormat_getInt32(trackFormat, AMEDIAFORMAT_KEY_PROFILE, &profile)) {
+            ASSERT_EQ(configParam.profile, profile) << "profile not as expected";
+        } else {
+            ASSERT_TRUE(false) << "profile not returned in extractor";
+        }
+    }
+
+    delete track;
+    AMediaFormat_delete(trackFormat);
+}
+
+INSTANTIATE_TEST_SUITE_P(ConfigParamTestAll, ConfigParamTest,
+                         ::testing::Values(make_pair("aac", 0),
+                                           make_pair("amr", 1),
+                                           make_pair("amr", 2),
+                                           make_pair("ogg", 3),
+                                           make_pair("wav", 4),
+                                           make_pair("flac", 5),
+                                           make_pair("ogg", 6),
+                                           make_pair("mp3", 7),
+                                           make_pair("midi", 8),
+                                           make_pair("mpeg2ts", 9),
+                                           make_pair("mkv", 10),
+                                           make_pair("mpeg4", 11),
+                                           make_pair("mkv", 12),
+                                           make_pair("mpeg2ps", 13)));
+
+INSTANTIATE_TEST_SUITE_P(ExtractorUnitTestAll, ExtractorFunctionalityTest,
                          ::testing::Values(make_pair("aac", "loudsoftaac.aac"),
                                            make_pair("amr", "testamr.amr"),
                                            make_pair("amr", "amrwb.wav"),
@@ -507,6 +759,7 @@
                                            make_pair("mpeg2ts", "segment000001.ts"),
                                            make_pair("flac", "sinesweepflac.flac"),
                                            make_pair("ogg", "testopus.opus"),
+                                           make_pair("midi", "midi_a.mid"),
                                            make_pair("mkv", "sinesweepvorbis.mkv"),
                                            make_pair("mpeg4", "sinesweepoggmp4.mp4"),
                                            make_pair("mp3", "sinesweepmp3lame.mp3"),
diff --git a/media/libaaudio/src/utility/AAudioUtilities.h b/media/libaaudio/src/utility/AAudioUtilities.h
index d2e4805..82eb77d 100644
--- a/media/libaaudio/src/utility/AAudioUtilities.h
+++ b/media/libaaudio/src/utility/AAudioUtilities.h
@@ -21,6 +21,7 @@
 #include <functional>
 #include <stdint.h>
 #include <sys/types.h>
+#include <unistd.h>
 
 #include <utils/Errors.h>
 #include <system/audio.h>
diff --git a/media/libaudioclient/AudioAttributes.cpp b/media/libaudioclient/AudioAttributes.cpp
index 1ee6930..ff4ba06 100644
--- a/media/libaudioclient/AudioAttributes.cpp
+++ b/media/libaudioclient/AudioAttributes.cpp
@@ -57,7 +57,7 @@
         parcel->writeInt32(0);
     } else {
         parcel->writeInt32(1);
-        parcel->writeUtf8AsUtf16(mAttributes.tags);
+        parcel->writeUtf8AsUtf16(std::string(mAttributes.tags));
     }
     parcel->writeInt32(static_cast<int32_t>(mStreamType));
     parcel->writeUint32(static_cast<uint32_t>(mGroupId));
diff --git a/media/libcpustats/ThreadCpuUsage.cpp b/media/libcpustats/ThreadCpuUsage.cpp
index 4b7549f..e71a7db 100644
--- a/media/libcpustats/ThreadCpuUsage.cpp
+++ b/media/libcpustats/ThreadCpuUsage.cpp
@@ -21,6 +21,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <time.h>
+#include <unistd.h>
 
 #include <utils/Log.h>
 
diff --git a/media/libeffects/lvm/lib/Common/src/DC_2I_D16_TRC_WRA_01_Private.h b/media/libeffects/lvm/lib/Common/src/DC_2I_D16_TRC_WRA_01_Private.h
index 6508b73..4170b3c 100644
--- a/media/libeffects/lvm/lib/Common/src/DC_2I_D16_TRC_WRA_01_Private.h
+++ b/media/libeffects/lvm/lib/Common/src/DC_2I_D16_TRC_WRA_01_Private.h
@@ -18,7 +18,7 @@
 #ifndef _DC_2I_D16_TRC_WRA_01_PRIVATE_H_
 #define _DC_2I_D16_TRC_WRA_01_PRIVATE_H_
 
-#define DC_FLOAT_STEP   0.0000002384f;
+#define DC_FLOAT_STEP   0.0000002384f
 
 /* The internal state variables are implemented in a (for the user)  hidden structure */
 /* In this (private) file, the internal structure is declared fro private use.*/
diff --git a/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp b/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp
index 1cb81a6..39f5bb6 100644
--- a/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp
+++ b/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp
@@ -1906,11 +1906,15 @@
             //ALOGV("\tReverb_command cmdCode Case: "
             //        "EFFECT_CMD_GET_PARAM start");
             effect_param_t *p = (effect_param_t *)pCmdData;
+            if (pCmdData == nullptr) {
+                ALOGW("\tLVM_ERROR : pCmdData is NULL");
+                return -EINVAL;
+            }
             if (SIZE_MAX - sizeof(effect_param_t) < (size_t)p->psize) {
                 android_errorWriteLog(0x534e4554, "26347509");
                 return -EINVAL;
             }
-            if (pCmdData == NULL || cmdSize < sizeof(effect_param_t) ||
+            if (cmdSize < sizeof(effect_param_t) ||
                     cmdSize < (sizeof(effect_param_t) + p->psize) ||
                     pReplyData == NULL || replySize == NULL ||
                     *replySize < (sizeof(effect_param_t) + p->psize)) {
diff --git a/media/libmedia/Android.bp b/media/libmedia/Android.bp
index 1df7c88..f963200 100644
--- a/media/libmedia/Android.bp
+++ b/media/libmedia/Android.bp
@@ -296,11 +296,13 @@
     header_libs: [
         "libstagefright_headers",
         "media_ndk_headers",
+        "jni_headers",
     ],
 
     export_header_lib_headers: [
         "libstagefright_headers",
         "media_ndk_headers",
+        "jni_headers",
     ],
 
     shared_libs: [
diff --git a/media/libmedia/MediaResource.cpp b/media/libmedia/MediaResource.cpp
index 0936a99..fe86d27 100644
--- a/media/libmedia/MediaResource.cpp
+++ b/media/libmedia/MediaResource.cpp
@@ -35,7 +35,7 @@
     this->value = value;
 }
 
-MediaResource::MediaResource(Type type, const std::vector<int8_t> &id, int64_t value) {
+MediaResource::MediaResource(Type type, const std::vector<uint8_t> &id, int64_t value) {
     this->type = type;
     this->subType = SubType::kUnspecifiedSubType;
     this->id = id;
@@ -66,11 +66,11 @@
 }
 
 //static
-MediaResource MediaResource::DrmSessionResource(const std::vector<int8_t> &id, int64_t value) {
+MediaResource MediaResource::DrmSessionResource(const std::vector<uint8_t> &id, int64_t value) {
     return MediaResource(Type::kDrmSession, id, value);
 }
 
-static String8 bytesToHexString(const std::vector<int8_t> &bytes) {
+static String8 bytesToHexString(const std::vector<uint8_t> &bytes) {
     String8 str;
     for (auto &b : bytes) {
         str.appendFormat("%02x", b);
diff --git a/media/libmedia/MidiIoWrapper.cpp b/media/libmedia/MidiIoWrapper.cpp
index e71ea2c..da272e3 100644
--- a/media/libmedia/MidiIoWrapper.cpp
+++ b/media/libmedia/MidiIoWrapper.cpp
@@ -18,8 +18,9 @@
 #define LOG_TAG "MidiIoWrapper"
 #include <utils/Log.h>
 
-#include <sys/stat.h>
 #include <fcntl.h>
+#include <sys/stat.h>
+#include <unistd.h>
 
 #include <media/MidiIoWrapper.h>
 #include <media/MediaExtractorPluginApi.h>
diff --git a/media/libmedia/include/media/MediaResource.h b/media/libmedia/include/media/MediaResource.h
index e7362c1..4927d28 100644
--- a/media/libmedia/include/media/MediaResource.h
+++ b/media/libmedia/include/media/MediaResource.h
@@ -35,13 +35,13 @@
     MediaResource() = delete;
     MediaResource(Type type, int64_t value);
     MediaResource(Type type, SubType subType, int64_t value);
-    MediaResource(Type type, const std::vector<int8_t> &id, int64_t value);
+    MediaResource(Type type, const std::vector<uint8_t> &id, int64_t value);
 
     static MediaResource CodecResource(bool secure, bool video);
     static MediaResource GraphicMemoryResource(int64_t value);
     static MediaResource CpuBoostResource();
     static MediaResource VideoBatteryResource();
-    static MediaResource DrmSessionResource(const std::vector<int8_t> &id, int64_t value);
+    static MediaResource DrmSessionResource(const std::vector<uint8_t> &id, int64_t value);
 };
 
 inline static const char *asString(MediaResource::Type i, const char *def = "??") {
diff --git a/media/libstagefright/MediaExtractorFactory.cpp b/media/libstagefright/MediaExtractorFactory.cpp
index 94267a1..af7da06 100644
--- a/media/libstagefright/MediaExtractorFactory.cpp
+++ b/media/libstagefright/MediaExtractorFactory.cpp
@@ -59,7 +59,7 @@
             sp<IMediaExtractor> ex;
             mediaExService->makeExtractor(
                     CreateIDataSourceFromDataSource(source),
-                    mime ? std::make_unique<std::string>(mime) : nullptr,
+                    mime ? std::optional<std::string>(mime) : std::nullopt,
                     &ex);
             return ex;
         } else {
diff --git a/media/libstagefright/codecs/amrnb/dec/test/AndroidTest.xml b/media/libstagefright/codecs/amrnb/dec/test/AndroidTest.xml
new file mode 100644
index 0000000..1a9e678
--- /dev/null
+++ b/media/libstagefright/codecs/amrnb/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 Amr-nb Decoder unit test">
+    <option name="test-suite-tag" value="AmrnbDecoderTest" />
+    <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+        <option name="cleanup" value="true" />
+        <option name="push" value="AmrnbDecoderTest->/data/local/tmp/AmrnbDecoderTest" />
+        <option name="push-file"
+            key="https://storage.googleapis.com/android_media/frameworks/av/media/libstagefright/codecs/amrnb/dec/test/AmrnbDecoderTest.zip?unzip=true"
+            value="/data/local/tmp/AmrnbDecoderTestRes/" />
+    </target_preparer>
+
+    <test class="com.android.tradefed.testtype.GTest" >
+        <option name="native-test-device-path" value="/data/local/tmp" />
+        <option name="module-name" value="AmrnbDecoderTest" />
+        <option name="native-test-flag" value="-P /data/local/tmp/AmrnbDecoderTestRes/" />
+    </test>
+</configuration>
diff --git a/media/libstagefright/codecs/amrnb/dec/test/README.md b/media/libstagefright/codecs/amrnb/dec/test/README.md
index 62e13ae..e9073e4 100644
--- a/media/libstagefright/codecs/amrnb/dec/test/README.md
+++ b/media/libstagefright/codecs/amrnb/dec/test/README.md
@@ -22,13 +22,18 @@
 adb push ${OUT}/data/nativetest/AmrnbDecoderTest/AmrnbDecoderTest /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-nb 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/amrnb/dec/test/AmrnbDecoderTest.zip). Download, unzip and push these files into device for testing.
+
 ```
-adb push amr-nb/. /data/local/tmp/
+adb push AmrnbDecoderTestRes/. /data/local/tmp/
 ```
 
 usage: AmrnbDecoderTest -P \<path_to_folder\>
 ```
-adb shell /data/local/tmp/AmrnbDecoderTest -P /data/local/tmp/
+adb shell /data/local/tmp/AmrnbDecoderTest -P /data/local/tmp/AmrnbDecoderTestRes/
+```
+Alternatively, the test can also be run using atest command.
+
+```
+atest AmrnbDecoderTest -- --enable-module-dynamic-download=true
 ```
diff --git a/media/libstagefright/codecs/gsm/dec/SoftGSM.h b/media/libstagefright/codecs/gsm/dec/SoftGSM.h
index ef86915..d5885a6 100644
--- a/media/libstagefright/codecs/gsm/dec/SoftGSM.h
+++ b/media/libstagefright/codecs/gsm/dec/SoftGSM.h
@@ -20,9 +20,7 @@
 
 #include <media/stagefright/omx/SimpleSoftOMXComponent.h>
 
-extern "C" {
 #include "gsm.h"
-}
 
 namespace android {
 
diff --git a/media/libstagefright/codecs/m4v_h263/dec/Android.bp b/media/libstagefright/codecs/m4v_h263/dec/Android.bp
index c67dc2b..0e18c10 100644
--- a/media/libstagefright/codecs/m4v_h263/dec/Android.bp
+++ b/media/libstagefright/codecs/m4v_h263/dec/Android.bp
@@ -1,6 +1,7 @@
 cc_library_static {
     name: "libstagefright_m4vh263dec",
     vendor_available: true,
+    host_supported: true,
     shared_libs: ["liblog"],
 
     srcs: [
@@ -38,11 +39,6 @@
         "src/zigzag_tab.cpp",
     ],
 
-    header_libs: [
-        "media_plugin_headers",
-        "libstagefright_headers"
-    ],
-
     local_include_dirs: ["src"],
     export_include_dirs: ["include"],
 
@@ -58,6 +54,12 @@
         ],
         cfi: true,
     },
+
+    target: {
+        darwin: {
+            enabled: false,
+        },
+    },
 }
 
 //###############################################################################
diff --git a/media/libstagefright/codecs/m4v_h263/fuzzer/Android.bp b/media/libstagefright/codecs/m4v_h263/fuzzer/Android.bp
new file mode 100644
index 0000000..aa79d37
--- /dev/null
+++ b/media/libstagefright/codecs/m4v_h263/fuzzer/Android.bp
@@ -0,0 +1,60 @@
+/******************************************************************************
+ *
+ * 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_fuzz {
+    name: "mpeg4_dec_fuzzer",
+    host_supported: true,
+    srcs: [
+        "mpeg4_h263_dec_fuzzer.cpp",
+    ],
+    static_libs: [
+        "libstagefright_m4vh263dec",
+        "liblog",
+    ],
+    cflags: [
+        "-DOSCL_IMPORT_REF=",
+        "-DMPEG4",
+    ],
+    target: {
+        darwin: {
+            enabled: false,
+        },
+    },
+}
+
+cc_fuzz {
+    name: "h263_dec_fuzzer",
+    host_supported: true,
+    srcs: [
+        "mpeg4_h263_dec_fuzzer.cpp",
+    ],
+    static_libs: [
+        "libstagefright_m4vh263dec",
+        "liblog",
+    ],
+    cflags: [
+        "-DOSCL_IMPORT_REF=",
+    ],
+    target: {
+        darwin: {
+            enabled: false,
+        },
+    },
+}
diff --git a/media/libstagefright/codecs/m4v_h263/fuzzer/README.md b/media/libstagefright/codecs/m4v_h263/fuzzer/README.md
new file mode 100644
index 0000000..c2a4f69
--- /dev/null
+++ b/media/libstagefright/codecs/m4v_h263/fuzzer/README.md
@@ -0,0 +1,57 @@
+# Fuzzer for libstagefright_m4vh263dec decoder
+
+## Plugin Design Considerations
+The fuzzer plugin for MPEG4/H263 is designed based on the understanding of the
+codec and tries to achieve the following:
+
+##### Maximize code coverage
+Dict files (dictionary files) are created for MPEG4 and H263 to ensure that the required start
+bytes are present in every input file that goes to the fuzzer.
+This ensures that decoder does not reject any input file in the first check
+
+##### Maximize utilization of input data
+The plugin feeds the entire input data to the codec using a loop.
+ * If the decode operation was successful, the input is advanced by the number of bytes consumed
+   in the decode call.
+ * If the decode operation was un-successful, the input is advanced by 1 byte so that the fuzzer
+   can proceed to feed the next frame.
+
+This ensures that the plugin tolerates any kind of input (empty, huge, malformed, etc)
+and doesnt `exit()` on any input and thereby increasing the chance of identifying vulnerabilities.
+
+##### Other considerations
+ * Two fuzzer binaries - mpeg4_dec_fuzzer and h263_dec_fuzzer are generated based on the presence
+   of a flag - 'MPEG4'
+ * The number of decode calls are kept to a maximum of 100 so that the fuzzer does not timeout.
+
+## Build
+
+This describes steps to build mpeg4_dec_fuzzer and h263_dec_fuzzer binary.
+
+### Android
+#### Steps to build
+Build the fuzzer
+```
+  $ mm -j$(nproc) mpeg4_dec_fuzzer
+  $ mm -j$(nproc) h263_dec_fuzzer
+```
+
+#### Steps to run
+Create a directory CORPUS_DIR and copy some MPEG4 or H263 files to that folder
+Push this directory to device.
+
+To run on device
+```
+  $ adb sync data
+  $ adb shell /data/fuzz/arm64/mpeg4_dec_fuzzer/mpeg4_dec_fuzzer CORPUS_DIR
+  $ adb shell /data/fuzz/arm64/h263_dec_fuzzer/h263_dec_fuzzer CORPUS_DIR
+```
+To run on host
+```
+  $ $ANDROID_HOST_OUT/fuzz/x86_64/mpeg4_dec_fuzzer/mpeg4_dec_fuzzer CORPUS_DIR
+  $ $ANDROID_HOST_OUT/fuzz/x86_64/h263_dec_fuzzer/h263_dec_fuzzer CORPUS_DIR
+```
+
+## References:
+ * http://llvm.org/docs/LibFuzzer.html
+ * https://github.com/google/oss-fuzz
diff --git a/media/libstagefright/codecs/m4v_h263/fuzzer/h263_dec_fuzzer.dict b/media/libstagefright/codecs/m4v_h263/fuzzer/h263_dec_fuzzer.dict
new file mode 100644
index 0000000..591d37e
--- /dev/null
+++ b/media/libstagefright/codecs/m4v_h263/fuzzer/h263_dec_fuzzer.dict
@@ -0,0 +1,2 @@
+# Start code (bytes 0-3)
+kw1="\x00\x00\x80\x02"
diff --git a/media/libstagefright/codecs/m4v_h263/fuzzer/mpeg4_dec_fuzzer.dict b/media/libstagefright/codecs/m4v_h263/fuzzer/mpeg4_dec_fuzzer.dict
new file mode 100644
index 0000000..76241a6
--- /dev/null
+++ b/media/libstagefright/codecs/m4v_h263/fuzzer/mpeg4_dec_fuzzer.dict
@@ -0,0 +1,2 @@
+# Start code (bytes 0-3)
+kw1="\x00\x00\x01\xB0"
diff --git a/media/libstagefright/codecs/m4v_h263/fuzzer/mpeg4_h263_dec_fuzzer.cpp b/media/libstagefright/codecs/m4v_h263/fuzzer/mpeg4_h263_dec_fuzzer.cpp
new file mode 100644
index 0000000..912c821
--- /dev/null
+++ b/media/libstagefright/codecs/m4v_h263/fuzzer/mpeg4_h263_dec_fuzzer.cpp
@@ -0,0 +1,205 @@
+/******************************************************************************
+ *
+ * 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 "mp4dec_api.h"
+#define MPEG4_MAX_WIDTH 1920
+#define MPEG4_MAX_HEIGHT 1080
+#define H263_MAX_WIDTH 352
+#define H263_MAX_HEIGHT 288
+#define DEFAULT_WIDTH 352
+#define DEFAULT_HEIGHT 288
+
+constexpr size_t kMaxNumDecodeCalls = 100;
+constexpr uint8_t kNumOutputBuffers = 2;
+constexpr int kLayer = 1;
+
+struct tagvideoDecControls;
+
+/* == ceil(num / den) * den. T must be integer type, alignment must be positive power of 2 */
+template <class T, class U>
+inline static const T align(const T &num, const U &den) {
+  return (num + (T)(den - 1)) & (T) ~(den - 1);
+}
+
+class Codec {
+ public:
+  Codec() = default;
+  ~Codec() { deInitDecoder(); }
+  bool initDecoder();
+  bool allocOutputBuffer(size_t outputBufferSize);
+  void freeOutputBuffer();
+  void handleResolutionChange();
+  void decodeFrames(const uint8_t *data, size_t size);
+  void deInitDecoder();
+
+ private:
+  tagvideoDecControls *mDecHandle = nullptr;
+  uint8_t *mOutputBuffer[kNumOutputBuffers];
+  bool mInitialized = false;
+  bool mFramesConfigured = false;
+#ifdef MPEG4
+  MP4DecodingMode mInputMode = MPEG4_MODE;
+  size_t mMaxWidth = MPEG4_MAX_WIDTH;
+  size_t mMaxHeight = MPEG4_MAX_HEIGHT;
+#else
+  MP4DecodingMode mInputMode = H263_MODE;
+  size_t mMaxWidth = H263_MAX_WIDTH;
+  size_t mMaxHeight = H263_MAX_HEIGHT;
+#endif
+  uint32_t mNumSamplesOutput = 0;
+  uint32_t mWidth = DEFAULT_WIDTH;
+  uint32_t mHeight = DEFAULT_HEIGHT;
+};
+
+bool Codec::initDecoder() {
+  mDecHandle = new tagvideoDecControls;
+  if (!mDecHandle) {
+    return false;
+  }
+  memset(mDecHandle, 0, sizeof(tagvideoDecControls));
+  return true;
+}
+
+bool Codec::allocOutputBuffer(size_t outputBufferSize) {
+  for (uint8_t i = 0; i < kNumOutputBuffers; ++i) {
+    if (!mOutputBuffer[i]) {
+      mOutputBuffer[i] = static_cast<uint8_t *>(malloc(outputBufferSize));
+      if (!mOutputBuffer[i]) {
+        return false;
+      }
+    }
+  }
+  return true;
+}
+
+void Codec::freeOutputBuffer() {
+  for (uint8_t i = 0; i < kNumOutputBuffers; ++i) {
+    if (mOutputBuffer[i]) {
+      free(mOutputBuffer[i]);
+      mOutputBuffer[i] = nullptr;
+    }
+  }
+}
+
+void Codec::handleResolutionChange() {
+  int32_t dispWidth, dispHeight;
+  PVGetVideoDimensions(mDecHandle, &dispWidth, &dispHeight);
+
+  int32_t bufWidth, bufHeight;
+  PVGetBufferDimensions(mDecHandle, &bufWidth, &bufHeight);
+
+  if (dispWidth != mWidth || dispHeight != mHeight) {
+    mWidth = dispWidth;
+    mHeight = dispHeight;
+  }
+}
+
+void Codec::decodeFrames(const uint8_t *data, size_t size) {
+  size_t outputBufferSize = align(mMaxWidth, 16) * align(mMaxHeight, 16) * 3 / 2;
+  uint8_t *start_code = const_cast<uint8_t *>(data);
+  static const uint8_t volInfo[] = {0x00, 0x00, 0x01, 0xB0};
+  bool volHeader = memcmp(start_code, volInfo, 4) == 0;
+  if (volHeader) {
+    PVCleanUpVideoDecoder(mDecHandle);
+    mInitialized = false;
+  }
+
+  if (!mInitialized) {
+    uint8_t *volData[1]{};
+    int32_t volSize = 0;
+
+    if (volHeader) { /* removed some codec config part */
+      volData[0] = const_cast<uint8_t *>(data);
+      volSize = size;
+    }
+
+    if (!PVInitVideoDecoder(mDecHandle, volData, &volSize, kLayer, mMaxWidth, mMaxHeight,
+                            mInputMode)) {
+      return;
+    }
+    mInitialized = true;
+    MP4DecodingMode actualMode = PVGetDecBitstreamMode(mDecHandle);
+    if (mInputMode != actualMode) {
+      return;
+    }
+
+    PVSetPostProcType(mDecHandle, 0);
+  }
+  size_t yFrameSize = sizeof(uint8) * mDecHandle->size;
+  if (outputBufferSize < yFrameSize * 3 / 2) {
+    return;
+  }
+  if (!allocOutputBuffer(outputBufferSize)) {
+    return;
+  }
+  size_t numDecodeCalls = 0;
+  while ((size > 0) && (numDecodeCalls < kMaxNumDecodeCalls)) {
+    if (!mFramesConfigured) {
+      PVSetReferenceYUV(mDecHandle, mOutputBuffer[1]);
+      mFramesConfigured = true;
+    }
+
+    // Need to check if header contains new info, e.g., width/height, etc.
+    VopHeaderInfo header_info;
+    uint32_t useExtTimestamp = (numDecodeCalls == 0);
+    int32_t tempSize = (int32_t)size;
+    uint8_t *bitstreamTmp = const_cast<uint8_t *>(data);
+    uint32_t timestamp = 0;
+    if (PVDecodeVopHeader(mDecHandle, &bitstreamTmp, &timestamp, &tempSize, &header_info,
+                          &useExtTimestamp, mOutputBuffer[mNumSamplesOutput & 1]) != PV_TRUE) {
+      return;
+    }
+
+    handleResolutionChange();
+
+    PVDecodeVopBody(mDecHandle, &tempSize);
+    uint32_t bytesConsumed = 1;
+    if (size > tempSize) {
+      bytesConsumed = size - tempSize;
+    }
+    data += bytesConsumed;
+    size -= bytesConsumed;
+    ++mNumSamplesOutput;
+    ++numDecodeCalls;
+  }
+  freeOutputBuffer();
+}
+
+void Codec::deInitDecoder() {
+  PVCleanUpVideoDecoder(mDecHandle);
+  delete mDecHandle;
+  mDecHandle = nullptr;
+  mInitialized = false;
+  freeOutputBuffer();
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+  if (size < 4) {
+    return 0;
+  }
+  Codec *codec = new Codec();
+  if (!codec) {
+    return 0;
+  }
+  if (codec->initDecoder()) {
+    codec->decodeFrames(data, size);
+  }
+  delete codec;
+  return 0;
+}
diff --git a/media/libstagefright/codecs/mp3dec/Android.bp b/media/libstagefright/codecs/mp3dec/Android.bp
index b630524..75b32bd 100644
--- a/media/libstagefright/codecs/mp3dec/Android.bp
+++ b/media/libstagefright/codecs/mp3dec/Android.bp
@@ -2,6 +2,7 @@
     name: "libstagefright_mp3dec",
     vendor_available: true,
 
+    host_supported:true,
     srcs: [
         "src/pvmp3_normalize.cpp",
         "src/pvmp3_alias_reduction.cpp",
@@ -72,6 +73,12 @@
         "-DOSCL_UNUSED_ARG(x)=(void)(x)",
         "-Werror",
     ],
+
+    target: {
+        darwin: {
+            enabled: false,
+        },
+    },
 }
 
 //###############################################################################
diff --git a/media/libstagefright/codecs/mp3dec/fuzzer/Android.bp b/media/libstagefright/codecs/mp3dec/fuzzer/Android.bp
new file mode 100644
index 0000000..2f0eda7
--- /dev/null
+++ b/media/libstagefright/codecs/mp3dec/fuzzer/Android.bp
@@ -0,0 +1,32 @@
+/******************************************************************************
+ *
+ * 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_fuzz {
+    name: "mp3_dec_fuzzer",
+    host_supported: true,
+
+    static_libs: [
+        "libstagefright_mp3dec",
+    ],
+
+    srcs: [
+        "mp3_dec_fuzzer.cpp",
+    ],
+}
diff --git a/media/libstagefright/codecs/mp3dec/fuzzer/README.md b/media/libstagefright/codecs/mp3dec/fuzzer/README.md
new file mode 100644
index 0000000..09dd5c3
--- /dev/null
+++ b/media/libstagefright/codecs/mp3dec/fuzzer/README.md
@@ -0,0 +1,56 @@
+# Fuzzer for libstagefright_mp3dec decoder
+
+## Plugin Design Considerations
+The fuzzer plugin for mp3 decoder is designed based on the understanding of the
+codec and tries to achieve the following:
+
+##### Maximize code coverage
+
+This fuzzer makes use of the following config parameters:
+1. Equalizer type (parameter name: `equalizerType`)
+
+| Parameter| Valid Values| Configured Value|
+|------------- |-------------| ----- |
+| `equalizerType` | 0. `flat ` 1. `bass_boost ` 2. `rock ` 3. `pop ` 4. `jazz ` 5. `classical ` 6. `talk ` 7. `flat_ ` | Bits 0, 1 and 2 of first byte of input stream |
+| `crcEnabled` | 0. `false ` 1. `true `| Bit 0 of second byte of input stream |
+
+##### Maximize utilization of input data
+The plugin feeds the entire input data to the codec using a loop.
+ * If the decode operation was successful, the input is advanced by the number
+   of bytes used by the decoder.
+ * If the decode operation was un-successful, the input is advanced by 1 byte
+   till it reaches a valid frame or end of stream.
+
+This ensures that the plugin tolerates any kind of input (empty, huge,
+malformed, etc) and doesnt `exit()` on any input and thereby increasing the
+chance of identifying vulnerabilities.
+
+## Build
+
+This describes steps to build mp3_dec_fuzzer binary.
+
+### Android
+
+#### Steps to build
+Build the fuzzer
+```
+  $ mm -j$(nproc) mp3_dec_fuzzer
+```
+
+#### Steps to run
+Create a directory CORPUS_DIR and copy some mp3 files to that folder.
+Push this directory to device.
+
+To run on device
+```
+  $ adb sync data
+  $ adb shell /data/fuzz/arm64/mp3_dec_fuzzer/mp3_dec_fuzzer CORPUS_DIR
+```
+To run on host
+```
+  $ $ANDROID_HOST_OUT/fuzz/x86_64/mp3_dec_fuzzer/mp3_dec_fuzzer CORPUS_DIR
+```
+
+## References:
+ * http://llvm.org/docs/LibFuzzer.html
+ * https://github.com/google/oss-fuzz
diff --git a/media/libstagefright/codecs/mp3dec/fuzzer/mp3_dec_fuzzer.cpp b/media/libstagefright/codecs/mp3dec/fuzzer/mp3_dec_fuzzer.cpp
new file mode 100644
index 0000000..847c8c4
--- /dev/null
+++ b/media/libstagefright/codecs/mp3dec/fuzzer/mp3_dec_fuzzer.cpp
@@ -0,0 +1,237 @@
+/******************************************************************************
+ *
+ * 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 <stdlib.h>
+#include <algorithm>
+
+#include <pvmp3decoder_api.h>
+
+constexpr int kMaxFrameSamples = 4608;
+constexpr int kMaxChannels = 2;
+constexpr e_equalization kEqualizerTypes[] = {flat, bass_boost, rock, pop,
+                                              jazz, classical,  talk, flat_};
+
+static bool parseMp3Header(uint32_t header, size_t *frame_size,
+                           uint32_t *out_sampling_rate = nullptr, uint32_t *out_channels = nullptr,
+                           uint32_t *out_bitrate = nullptr, uint32_t *out_num_samples = nullptr) {
+  *frame_size = 0;
+  if (out_sampling_rate) *out_sampling_rate = 0;
+  if (out_channels) *out_channels = 0;
+  if (out_bitrate) *out_bitrate = 0;
+  if (out_num_samples) *out_num_samples = 0;
+
+  if ((header & 0xffe00000) != 0xffe00000) {
+    return false;
+  }
+  unsigned version = (header >> 19) & 3;
+  if (version == 0x01) {
+    return false;
+  }
+  unsigned layer = (header >> 17) & 3;
+  if (layer == 0x00) {
+    return false;
+  }
+  unsigned bitrate_index = (header >> 12) & 0x0f;
+  if (bitrate_index == 0 || bitrate_index == 0x0f) {
+    return false;
+  }
+  unsigned sampling_rate_index = (header >> 10) & 3;
+  if (sampling_rate_index == 3) {
+    return false;
+  }
+  static const int kSamplingRateV1[] = {44100, 48000, 32000};
+  int sampling_rate = kSamplingRateV1[sampling_rate_index];
+  if (version == 2 /* V2 */) {
+    sampling_rate /= 2;
+  } else if (version == 0 /* V2.5 */) {
+    sampling_rate /= 4;
+  }
+
+  unsigned padding = (header >> 9) & 1;
+
+  if (layer == 3) {  // layer I
+    static const int kBitrateV1[] = {32,  64,  96,  128, 160, 192, 224,
+                                     256, 288, 320, 352, 384, 416, 448};
+    static const int kBitrateV2[] = {32,  48,  56,  64,  80,  96,  112,
+                                     128, 144, 160, 176, 192, 224, 256};
+
+    int bitrate =
+        (version == 3 /* V1 */) ? kBitrateV1[bitrate_index - 1] : kBitrateV2[bitrate_index - 1];
+
+    if (out_bitrate) {
+      *out_bitrate = bitrate;
+    }
+    *frame_size = (12000 * bitrate / sampling_rate + padding) * 4;
+    if (out_num_samples) {
+      *out_num_samples = 384;
+    }
+  } else {  // layer II or III
+    static const int kBitrateV1L2[] = {32,  48,  56,  64,  80,  96,  112,
+                                       128, 160, 192, 224, 256, 320, 384};
+    static const int kBitrateV1L3[] = {32,  40,  48,  56,  64,  80,  96,
+                                       112, 128, 160, 192, 224, 256, 320};
+    static const int kBitrateV2[] = {8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160};
+    int bitrate;
+    if (version == 3 /* V1 */) {
+      bitrate =
+          (layer == 2 /* L2 */) ? kBitrateV1L2[bitrate_index - 1] : kBitrateV1L3[bitrate_index - 1];
+
+      if (out_num_samples) {
+        *out_num_samples = 1152;
+      }
+    } else {  // V2 (or 2.5)
+      bitrate = kBitrateV2[bitrate_index - 1];
+      if (out_num_samples) {
+        *out_num_samples = (layer == 1 /* L3 */) ? 576 : 1152;
+      }
+    }
+
+    if (out_bitrate) {
+      *out_bitrate = bitrate;
+    }
+
+    if (version == 3 /* V1 */) {
+      *frame_size = 144000 * bitrate / sampling_rate + padding;
+    } else {  // V2 or V2.5
+      size_t tmp = (layer == 1 /* L3 */) ? 72000 : 144000;
+      *frame_size = tmp * bitrate / sampling_rate + padding;
+    }
+  }
+
+  if (out_sampling_rate) {
+    *out_sampling_rate = sampling_rate;
+  }
+
+  if (out_channels) {
+    int channel_mode = (header >> 6) & 3;
+    *out_channels = (channel_mode == 3) ? 1 : 2;
+  }
+
+  return true;
+}
+
+static uint32_t U32_AT(const uint8_t *ptr) {
+  return ptr[0] << 24 | ptr[1] << 16 | ptr[2] << 8 | ptr[3];
+}
+
+static bool checkHeader(uint8 *header, size_t inSize) {
+  size_t frameSize;
+  size_t totalInSize = 0;
+  bool isValidBuffer = false;
+
+  while (totalInSize + 4 < inSize) {
+    isValidBuffer = true;
+    uint32_t val = U32_AT(header + totalInSize);
+    if (!parseMp3Header(val, &frameSize, nullptr, nullptr, nullptr, nullptr)) {
+      return false;
+    }
+    totalInSize += frameSize;
+  }
+
+  return (isValidBuffer);
+}
+
+class Codec {
+ public:
+  Codec() = default;
+  ~Codec() { deInitDecoder(); }
+
+  bool initDecoder();
+  void decodeFrames(uint8_t *data, size_t size);
+  void deInitDecoder();
+
+ private:
+  tPVMP3DecoderExternal *mConfig = nullptr;
+  void *mDecoderBuf = nullptr;
+};
+
+bool Codec::initDecoder() {
+  mConfig = new tPVMP3DecoderExternal{};
+  if (!mConfig) {
+    return false;
+  }
+  size_t decoderBufSize = pvmp3_decoderMemRequirements();
+  mDecoderBuf = malloc(decoderBufSize);
+  if (!mDecoderBuf) {
+    return false;
+  }
+  memset(mDecoderBuf, 0x0, decoderBufSize);
+  pvmp3_InitDecoder(mConfig, mDecoderBuf);
+  return true;
+}
+
+void Codec::decodeFrames(uint8_t *data, size_t size) {
+  uint8_t equalizerTypeValue = (data[0] & 0x7);
+  mConfig->equalizerType = kEqualizerTypes[equalizerTypeValue];
+  mConfig->crcEnabled = data[1] & 0x1;
+
+  while (size > 0) {
+    bool status = checkHeader(data, size);
+    if (!status) {
+      size--;
+      data++;
+      continue;
+    }
+    size_t outBufSize = kMaxFrameSamples * kMaxChannels;
+    size_t usedBytes = 0;
+    int16_t outputBuf[outBufSize];
+    mConfig->inputBufferCurrentLength = size;
+    mConfig->inputBufferUsedLength = 0;
+    mConfig->inputBufferMaxLength = 0;
+    mConfig->pInputBuffer = data;
+    mConfig->pOutputBuffer = outputBuf;
+    mConfig->outputFrameSize = outBufSize / sizeof(int16_t);
+
+    ERROR_CODE decoderErr;
+    decoderErr = pvmp3_framedecoder(mConfig, mDecoderBuf);
+    if (decoderErr != NO_DECODING_ERROR) {
+      size--;
+      data++;
+    } else {
+      usedBytes = std::min((int32_t)size, mConfig->inputBufferUsedLength);
+      size -= usedBytes;
+      data += usedBytes;
+    }
+  }
+}
+
+void Codec::deInitDecoder() {
+  if (mDecoderBuf) {
+    free(mDecoderBuf);
+    mDecoderBuf = nullptr;
+  }
+  delete mConfig;
+  mConfig = nullptr;
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+  if (size < 4) {
+    return 0;
+  }
+  Codec *codec = new Codec();
+  if (!codec) {
+    return 0;
+  }
+  if (codec->initDecoder()) {
+    codec->decodeFrames(const_cast<uint8_t *>(data), size);
+  }
+  delete codec;
+  return 0;
+}
diff --git a/media/libstagefright/foundation/OpusHeader.cpp b/media/libstagefright/foundation/OpusHeader.cpp
index f5687e0..784e802 100644
--- a/media/libstagefright/foundation/OpusHeader.cpp
+++ b/media/libstagefright/foundation/OpusHeader.cpp
@@ -126,12 +126,20 @@
     }
     header->num_streams = data[kOpusHeaderNumStreamsOffset];
     header->num_coupled = data[kOpusHeaderNumCoupledStreamsOffset];
-    if (header->num_streams + header->num_coupled != header->channels) {
-        ALOGV("Inconsistent channel mapping.");
+    if (header->num_coupled > header->num_streams ||
+        header->num_streams + header->num_coupled != header->channels) {
+        ALOGV("Inconsistent channel mapping, streams: %d coupled: %d channels: %d",
+        header->num_streams, header->num_coupled, header->channels);
         return false;
     }
-    for (int i = 0; i < header->channels; ++i)
-        header->stream_map[i] = data[kOpusHeaderStreamMapOffset + i];
+    for (int i = 0; i < header->channels; ++i) {
+        uint8_t value = data[kOpusHeaderStreamMapOffset + i];
+        if (value != 255 && value >= header->channels) {
+            ALOGV("Invalid channel mapping for index %i : %d", i, value);
+            return false;
+        }
+        header->stream_map[i] = value;
+    }
     return true;
 }
 
diff --git a/media/libstagefright/foundation/tests/AVCUtils/AVCUtilsTestEnvironment.h b/media/libstagefright/foundation/tests/AVCUtils/AVCUtilsTestEnvironment.h
new file mode 100644
index 0000000..b28a7bc
--- /dev/null
+++ b/media/libstagefright/foundation/tests/AVCUtils/AVCUtilsTestEnvironment.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 __AVC_UTILS_TEST_ENVIRONMENT_H__
+#define __AVC_UTILS_TEST_ENVIRONMENT_H__
+
+#include <gtest/gtest.h>
+
+#include <getopt.h>
+
+using namespace std;
+
+class AVCUtilsTestEnvironment : public::testing::Environment {
+  public:
+    AVCUtilsTestEnvironment() : 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 AVCUtilsTestEnvironment::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  // __AVC_UTILS_TEST_ENVIRONMENT_H__
diff --git a/media/libstagefright/foundation/tests/AVCUtils/AVCUtilsUnitTest.cpp b/media/libstagefright/foundation/tests/AVCUtils/AVCUtilsUnitTest.cpp
new file mode 100644
index 0000000..77a8599
--- /dev/null
+++ b/media/libstagefright/foundation/tests/AVCUtils/AVCUtilsUnitTest.cpp
@@ -0,0 +1,411 @@
+/*
+ * 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 "AVCUtilsUnitTest"
+#include <utils/Log.h>
+
+#include <fstream>
+
+#include "media/stagefright/foundation/ABitReader.h"
+#include "media/stagefright/foundation/avc_utils.h"
+
+#include "AVCUtilsTestEnvironment.h"
+
+constexpr size_t kSmallBufferSize = 2;
+constexpr uint8_t kSPSmask = 0x1f;
+constexpr uint8_t kSPSStartCode = 0x07;
+constexpr uint8_t kConfigVersion = 0x01;
+
+using namespace android;
+
+static AVCUtilsTestEnvironment *gEnv = nullptr;
+
+class MpegAudioUnitTest
+    : public ::testing::TestWithParam<
+              tuple</*audioHeader*/ uint32_t, /*frameSize*/ int32_t, /*sampleRate*/ int32_t,
+                    /*numChannels*/ int32_t, /*bitRate*/ int32_t, /*numSamples*/ int32_t>> {};
+
+class VOLDimensionTest
+    : public ::testing::TestWithParam<
+              tuple</*fileName*/ string, /*volWidth*/ int32_t, /*volHeight*/ int32_t>> {};
+
+class AVCUtils {
+  public:
+    bool SetUpAVCUtils(string fileName, string infoFileName) {
+        mInputFile = gEnv->getRes() + fileName;
+        mInputFileStream.open(mInputFile, ifstream::in);
+        if (!mInputFileStream.is_open()) return false;
+
+        mInfoFile = gEnv->getRes() + infoFileName;
+        mInfoFileStream.open(mInfoFile, ifstream::in);
+        if (!mInputFileStream.is_open()) return false;
+        return true;
+    }
+
+    ~AVCUtils() {
+        if (mInputFileStream.is_open()) mInputFileStream.close();
+        if (mInfoFileStream.is_open()) mInfoFileStream.close();
+    }
+
+    string mInputFile;
+    string mInfoFile;
+
+    ifstream mInputFileStream;
+    ifstream mInfoFileStream;
+};
+
+class AVCDimensionTest
+    : public AVCUtils,
+      public ::testing::TestWithParam<
+              tuple</*fileName*/ string, /*infoFileName*/ string,
+                    /*avcWidth*/ size_t, /*avcHeight*/ size_t, /*numberOfNALUnits*/ int32_t>> {
+  public:
+    virtual void SetUp() override {
+        tuple<string, string, size_t, size_t, size_t> params = GetParam();
+        string fileName = get<0>(params);
+        string infoFileName = get<1>(params);
+        AVCUtils::SetUpAVCUtils(fileName, infoFileName);
+
+        mFrameWidth = get<2>(params);
+        mFrameHeight = get<3>(params);
+        mNalUnitsExpected = get<4>(params);
+    }
+
+    size_t mFrameWidth;
+    size_t mFrameHeight;
+    int32_t mNalUnitsExpected;
+};
+
+class AvccBoxTest : public AVCDimensionTest {
+  public:
+    virtual void SetUp() override { AVCDimensionTest::SetUp(); }
+};
+
+class AVCFrameTest
+    : public AVCUtils,
+      public ::testing::TestWithParam<pair</*fileName*/ string, /*infoFileName*/ string>> {
+  public:
+    virtual void SetUp() override {
+        string fileName = GetParam().first;
+        string infoFileName = GetParam().second;
+        AVCUtils::SetUpAVCUtils(fileName, infoFileName);
+    }
+};
+
+TEST_P(MpegAudioUnitTest, AudioProfileTest) {
+    tuple<uint32_t, size_t, int, int, int, int> params = GetParam();
+    uint32_t header = get<0>(params);
+
+    size_t audioFrameSize = get<1>(params);
+    int audioSampleRate = get<2>(params);
+    int audioNumChannels = get<3>(params);
+    int audioBitRate = get<4>(params);
+    int audioNumSamples = get<5>(params);
+
+    size_t frameSize = 0;
+    int sampleRate = 0;
+    int numChannels = 0;
+    int bitRate = 0;
+    int numSamples = 0;
+
+    bool status = GetMPEGAudioFrameSize(header, &frameSize, &sampleRate, &numChannels, &bitRate,
+                                        &numSamples);
+    ASSERT_TRUE(status) << "Failed to get Audio properties";
+
+    ASSERT_EQ(frameSize, audioFrameSize) << "Wrong frame size found";
+
+    ASSERT_EQ(sampleRate, audioSampleRate) << "Wrong sample rate found";
+
+    ASSERT_EQ(numChannels, audioNumChannels) << "Wrong number of channels found";
+
+    ASSERT_EQ(bitRate, audioBitRate) << "Wrong bit rate found";
+
+    ASSERT_EQ(numSamples, audioNumSamples) << "Wrong number of samples found";
+}
+
+TEST_P(VOLDimensionTest, DimensionTest) {
+    tuple<string, int32_t, int32_t> params = GetParam();
+    string inputFile = gEnv->getRes() + get<0>(params);
+    ifstream inputFileStream;
+    inputFileStream.open(inputFile, ifstream::in);
+    ASSERT_TRUE(inputFileStream.is_open()) << "Failed to open: " << inputFile;
+
+    struct stat buf;
+    int8_t err = stat(inputFile.c_str(), &buf);
+    ASSERT_EQ(err, 0) << "Failed to get information for file: " << inputFile;
+
+    size_t fileSize = buf.st_size;
+    ASSERT_NE(fileSize, 0) << "Invalid file size found";
+
+    const uint8_t *volBuffer = new uint8_t[fileSize];
+    ASSERT_NE(volBuffer, nullptr) << "Failed to allocate VOL buffer of size: " << fileSize;
+
+    inputFileStream.read((char *)(volBuffer), fileSize);
+    ASSERT_EQ(inputFileStream.gcount(), fileSize)
+            << "Failed to read complete file, bytes read: " << inputFileStream.gcount();
+
+    int32_t width = get<1>(params);
+    int32_t height = get<2>(params);
+    int32_t volWidth = -1;
+    int32_t volHeight = -1;
+
+    bool status = ExtractDimensionsFromVOLHeader(volBuffer, fileSize, &volWidth, &volHeight);
+    ASSERT_TRUE(status)
+            << "Failed to get VOL dimensions from function: ExtractDimensionsFromVOLHeader()";
+
+    ASSERT_EQ(volWidth, width) << "Expected width: " << width << "Found: " << volWidth;
+
+    ASSERT_EQ(volHeight, height) << "Expected height: " << height << "Found: " << volHeight;
+
+    delete[] volBuffer;
+}
+
+TEST_P(AVCDimensionTest, DimensionTest) {
+    int32_t numNalUnits = 0;
+    int32_t avcWidth = -1;
+    int32_t avcHeight = -1;
+    string line;
+    string type;
+    size_t chunkLength;
+    while (getline(mInfoFileStream, line)) {
+        istringstream stringLine(line);
+        stringLine >> type >> chunkLength;
+        ASSERT_GT(chunkLength, 0) << "Length of the data chunk must be greater than zero";
+
+        const uint8_t *data = new uint8_t[chunkLength];
+        ASSERT_NE(data, nullptr) << "Failed to create a data buffer of size: " << chunkLength;
+
+        const uint8_t *nalStart;
+        size_t nalSize;
+
+        mInputFileStream.read((char *)data, chunkLength);
+        ASSERT_EQ(mInputFileStream.gcount(), chunkLength)
+                << "Failed to read complete file, bytes read: " << mInputFileStream.gcount();
+
+        size_t smallBufferSize = kSmallBufferSize;
+        const uint8_t *sanityData = new uint8_t[smallBufferSize];
+        memcpy((void *)sanityData, (void *)data, smallBufferSize);
+
+        status_t result = getNextNALUnit(&sanityData, &smallBufferSize, &nalStart, &nalSize, true);
+        ASSERT_EQ(result, -EAGAIN) << "Invalid result found when wrong NAL unit passed";
+
+        while (!getNextNALUnit(&data, &chunkLength, &nalStart, &nalSize, true)) {
+            numNalUnits++;
+            // Check if it's an SPS
+            if ((nalStart[0] & kSPSmask) != kSPSStartCode) continue;
+            ASSERT_TRUE(nalSize > 0) << "NAL unit size must be greater than 0";
+
+            sp<ABuffer> spsBuffer = new ABuffer(nalSize);
+            ASSERT_NE(spsBuffer, nullptr) << "ABuffer returned null for size: " << nalSize;
+
+            memcpy(spsBuffer->data(), nalStart, nalSize);
+            FindAVCDimensions(spsBuffer, &avcWidth, &avcHeight);
+            spsBuffer.clear();
+            ASSERT_EQ(avcWidth, mFrameWidth)
+                    << "Expected width: " << mFrameWidth << "Found: " << avcWidth;
+
+            ASSERT_EQ(avcHeight, mFrameHeight)
+                    << "Expected height: " << mFrameHeight << "Found: " << avcHeight;
+        }
+        delete[] data;
+    }
+    if (mNalUnitsExpected < 0) {
+        ASSERT_GT(numNalUnits, 0) << "Failed to find an NAL Unit";
+    } else {
+        ASSERT_EQ(numNalUnits, mNalUnitsExpected)
+                << "Expected number of NAL units: " << mNalUnitsExpected
+                << " found: " << numNalUnits;
+    }
+}
+
+TEST_P(AvccBoxTest, AvccBoxValidationTest) {
+    int32_t avcWidth = -1;
+    int32_t avcHeight = -1;
+    int32_t accessUnitLength = 0;
+    int32_t profile = -1;
+    int32_t level = -1;
+    string line;
+    string type;
+    size_t chunkLength;
+    while (getline(mInfoFileStream, line)) {
+        istringstream stringLine(line);
+        stringLine >> type >> chunkLength;
+
+        if (type.compare("SPS") && type.compare("PPS")) continue;
+        ASSERT_GT(chunkLength, 0) << "Length of the data chunk must be greater than zero";
+
+        accessUnitLength += chunkLength;
+
+        if (!type.compare("SPS")) {
+            const uint8_t *data = new uint8_t[chunkLength];
+            ASSERT_NE(data, nullptr) << "Failed to create a data buffer of size: " << chunkLength;
+
+            const uint8_t *nalStart;
+            size_t nalSize;
+
+            mInputFileStream.read((char *)data, (uint32_t)chunkLength);
+            ASSERT_EQ(mInputFileStream.gcount(), chunkLength)
+                    << "Failed to read complete file, bytes read: " << mInputFileStream.gcount();
+
+            while (!getNextNALUnit(&data, &chunkLength, &nalStart, &nalSize, true)) {
+                // Check if it's an SPS
+                ASSERT_TRUE(nalSize > 0 && (nalStart[0] & kSPSmask) == kSPSStartCode)
+                        << "Failed to get SPS";
+
+                ASSERT_GE(nalSize, 4) << "SPS size must be greater than or equal to 4";
+
+                profile = nalStart[1];
+                level = nalStart[3];
+            }
+            delete[] data;
+        }
+    }
+    const uint8_t *accessUnitData = new uint8_t[accessUnitLength];
+    ASSERT_NE(accessUnitData, nullptr) << "Failed to create a buffer of size: " << accessUnitLength;
+
+    mInputFileStream.seekg(0, ios::beg);
+    mInputFileStream.read((char *)accessUnitData, accessUnitLength);
+    ASSERT_EQ(mInputFileStream.gcount(), accessUnitLength)
+            << "Failed to read complete file, bytes read: " << mInputFileStream.gcount();
+
+    sp<ABuffer> accessUnit = new ABuffer(accessUnitLength);
+    ASSERT_NE(accessUnit, nullptr)
+            << "Failed to create an android data buffer of size: " << accessUnitLength;
+
+    memcpy(accessUnit->data(), accessUnitData, accessUnitLength);
+    sp<ABuffer> csdDataBuffer = MakeAVCCodecSpecificData(accessUnit, &avcWidth, &avcHeight);
+    ASSERT_NE(csdDataBuffer, nullptr) << "No data returned from MakeAVCCodecSpecificData()";
+
+    ASSERT_EQ(avcWidth, mFrameWidth) << "Expected width: " << mFrameWidth << "Found: " << avcWidth;
+
+    ASSERT_EQ(avcHeight, mFrameHeight)
+            << "Expected height: " << mFrameHeight << "Found: " << avcHeight;
+
+    uint8_t *csdData = csdDataBuffer->data();
+    ASSERT_EQ(*csdData, kConfigVersion) << "Invalid configuration version";
+
+    ASSERT_GE(csdDataBuffer->size(), 4) << "CSD data size must be greater than or equal to 4";
+
+    ASSERT_EQ(*(csdData + 1), profile)
+            << "Expected AVC profile: " << profile << " found: " << *(csdData + 1);
+
+    ASSERT_EQ(*(csdData + 3), level)
+            << "Expected AVC level: " << level << " found: " << *(csdData + 3);
+    csdDataBuffer.clear();
+    delete[] accessUnitData;
+    accessUnit.clear();
+}
+
+TEST_P(AVCFrameTest, FrameTest) {
+    string line;
+    string type;
+    size_t chunkLength;
+    int32_t frameLayerID;
+    while (getline(mInfoFileStream, line)) {
+        uint32_t layerID = 0;
+        istringstream stringLine(line);
+        stringLine >> type >> chunkLength >> frameLayerID;
+        ASSERT_GT(chunkLength, 0) << "Length of the data chunk must be greater than zero";
+
+        char *data = new char[chunkLength];
+        ASSERT_NE(data, nullptr) << "Failed to allocation data buffer of size: " << chunkLength;
+
+        mInputFileStream.read(data, chunkLength);
+        ASSERT_EQ(mInputFileStream.gcount(), chunkLength)
+                << "Failed to read complete file, bytes read: " << mInputFileStream.gcount();
+
+        if (!type.compare("IDR")) {
+            bool isIDR = IsIDR((uint8_t *)data, chunkLength);
+            ASSERT_TRUE(isIDR);
+
+            layerID = FindAVCLayerId((uint8_t *)data, chunkLength);
+            ASSERT_EQ(layerID, frameLayerID) << "Wrong layer ID found";
+        } else if (!type.compare("P") || !type.compare("B")) {
+            sp<ABuffer> accessUnit = new ABuffer(chunkLength);
+            ASSERT_NE(accessUnit, nullptr) << "Unable to create access Unit";
+
+            memcpy(accessUnit->data(), data, chunkLength);
+            bool isReferenceFrame = IsAVCReferenceFrame(accessUnit);
+            ASSERT_TRUE(isReferenceFrame);
+
+            accessUnit.clear();
+            layerID = FindAVCLayerId((uint8_t *)data, chunkLength);
+            ASSERT_EQ(layerID, frameLayerID) << "Wrong layer ID found";
+        }
+        delete[] data;
+    }
+}
+
+INSTANTIATE_TEST_SUITE_P(AVCUtilsTestAll, MpegAudioUnitTest,
+                         ::testing::Values(make_tuple(0xFFFB9204, 418, 44100, 2, 128, 1152),
+                                           make_tuple(0xFFFB7604, 289, 48000, 2, 96, 1152),
+                                           make_tuple(0xFFFE5604, 164, 48000, 2, 160, 384)));
+
+// Info File contains the type and length for each chunk/frame
+INSTANTIATE_TEST_SUITE_P(
+        AVCUtilsTestAll, AVCDimensionTest,
+        ::testing::Values(make_tuple("crowd_8x8p50f32_200kbps_bp.h264",
+                                     "crowd_8x8p50f32_200kbps_bp.info", 8, 8, 11),
+                          make_tuple("crowd_640x360p24f300_1000kbps_bp.h264",
+                                     "crowd_640x360p24f300_1000kbps_bp.info", 640, 360, 11),
+                          make_tuple("crowd_1280x720p30f300_5000kbps_bp.h264",
+                                     "crowd_1280x720p30f300_5000kbps_bp.info", 1280, 720, 12),
+                          make_tuple("crowd_1920x1080p50f300_12000kbps_bp.h264",
+                                     "crowd_1920x1080p50f300_12000kbps_bp.info", 1920, 1080, 14),
+                          make_tuple("crowd_3840x2160p60f300_68000kbps_bp.h264",
+                                     "crowd_3840x2160p60f300_68000kbps_bp.info", 3840, 2160, 14)));
+
+// Info File contains the type and length for each chunk/frame
+INSTANTIATE_TEST_SUITE_P(
+        AVCUtilsTestAll, AvccBoxTest,
+        ::testing::Values(make_tuple("crowd_8x8p50f32_200kbps_bp.h264",
+                                     "crowd_8x8p50f32_200kbps_bp.info", 8, 8, 11),
+                          make_tuple("crowd_1280x720p30f300_5000kbps_bp.h264",
+                                     "crowd_1280x720p30f300_5000kbps_bp.info", 1280, 720, 12),
+                          make_tuple("crowd_1920x1080p50f300_12000kbps_bp.h264",
+                                     "crowd_1920x1080p50f300_12000kbps_bp.info", 1920, 1080, 14)));
+
+// Info File contains the type and length for each chunk/frame
+INSTANTIATE_TEST_SUITE_P(AVCUtilsTestAll, VOLDimensionTest,
+                         ::testing::Values(make_tuple("volData_720_480", 720, 480),
+                                           make_tuple("volData_1280_720", 1280, 720),
+                                           make_tuple("volData_1920_1080", 1920, 1080)));
+
+// Info File contains the type, length and layer ID for each chunk/frame
+INSTANTIATE_TEST_SUITE_P(AVCUtilsTestAll, AVCFrameTest,
+                         ::testing::Values(make_tuple("crowd_8x8p50f32_200kbps_bp.h264",
+                                                      "crowd_8x8p50f32_200kbps_bp.info"),
+                                           make_tuple("crowd_640x360p24f300_1000kbps_bp.h264",
+                                                      "crowd_640x360p24f300_1000kbps_bp.info"),
+                                           make_tuple("crowd_1280x720p30f300_5000kbps_bp.h264",
+                                                      "crowd_1280x720p30f300_5000kbps_bp.info"),
+                                           make_tuple("crowd_1920x1080p50f300_12000kbps_bp.h264",
+                                                      "crowd_1920x1080p50f300_12000kbps_bp.info"),
+                                           make_tuple("crowd_3840x2160p60f300_68000kbps_bp.h264",
+                                                      "crowd_3840x2160p60f300_68000kbps_bp.info")));
+
+int main(int argc, char **argv) {
+    gEnv = new AVCUtilsTestEnvironment();
+    ::testing::AddGlobalTestEnvironment(gEnv);
+    ::testing::InitGoogleTest(&argc, argv);
+    int status = gEnv->initFromOptions(argc, argv);
+    if (status == 0) {
+        status = RUN_ALL_TESTS();
+        ALOGV("Test result = %d\n", status);
+    }
+    return status;
+}
diff --git a/media/libstagefright/foundation/tests/AVCUtils/Android.bp b/media/libstagefright/foundation/tests/AVCUtils/Android.bp
new file mode 100644
index 0000000..5d0e481
--- /dev/null
+++ b/media/libstagefright/foundation/tests/AVCUtils/Android.bp
@@ -0,0 +1,51 @@
+/*
+ * 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: "AVCUtilsUnitTest",
+    gtest: true,
+
+    srcs: [
+        "AVCUtilsUnitTest.cpp",
+    ],
+
+    shared_libs: [
+        "libutils",
+        "liblog",
+    ],
+
+    static_libs: [
+        "libstagefright",
+        "libstagefright_foundation",
+    ],
+
+    include_dirs: [
+        "frameworks/av/media/libstagefright/foundation",
+    ],
+
+    cflags: [
+        "-Werror",
+        "-Wall",
+    ],
+
+    sanitize: {
+        cfi: true,
+        misc_undefined: [
+            "unsigned-integer-overflow",
+            "signed-integer-overflow",
+        ],
+    },
+}
diff --git a/media/libstagefright/foundation/tests/AVCUtils/AndroidTest.xml b/media/libstagefright/foundation/tests/AVCUtils/AndroidTest.xml
new file mode 100644
index 0000000..6a088a8
--- /dev/null
+++ b/media/libstagefright/foundation/tests/AVCUtils/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 AVC Utils unit tests">
+    <option name="test-suite-tag" value="AVCUtilsUnitTest" />
+    <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+        <option name="cleanup" value="false" />
+        <option name="push" value="AVCUtilsUnitTest->/data/local/tmp/AVCUtilsUnitTest" />
+        <option name="push-file"
+            key="https://storage.googleapis.com/android_media/frameworks/av/media/libstagefright/foundation/tests/AVCUtils/AVCUtilsUnitTest.zip?unzip=true"
+            value="/data/local/tmp/AVCUtilsUnitTest/" />
+    </target_preparer>
+
+    <test class="com.android.tradefed.testtype.GTest" >
+        <option name="native-test-device-path" value="/data/local/tmp" />
+        <option name="module-name" value="AVCUtilsUnitTest" />
+        <option name="native-test-flag" value="-P /data/local/tmp/AVCUtilsUnitTest/" />
+    </test>
+</configuration>
diff --git a/media/libstagefright/foundation/tests/AVCUtils/README.md b/media/libstagefright/foundation/tests/AVCUtils/README.md
new file mode 100644
index 0000000..609d72e
--- /dev/null
+++ b/media/libstagefright/foundation/tests/AVCUtils/README.md
@@ -0,0 +1,39 @@
+## Media Testing ##
+---
+#### AVCUtils Test
+The AVC Utility Unit Test Suite validates the avc_utils librariy available in libstagefright/foundation.
+
+Run the following steps to build the test suite:
+```
+m AVCUtilsUnitTest
+```
+
+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/AVCUtilsUnitTest/AVCUtilsUnitTest /data/local/tmp/
+```
+
+To test 32-bit binary push binaries from nativetest.
+```
+adb push ${OUT}/data/nativetest/AVCUtilsUnitTest/AVCUtilsUnitTest /data/local/tmp/
+```
+
+The resource file for the tests is taken from [here](https://storage.googleapis.com/android_media/frameworks/av/media/libstagefright/foundation/tests/AVCUtils/AVCUtilsUnitTest.zip). Download, unzip and push these files into device for testing.
+
+```
+adb push AVCUtilsUnitTest /data/local/tmp/
+```
+
+usage: AVCUtilsUnitTest -P \<path_to_folder\>
+```
+adb shell /data/local/tmp/AVCUtilsUnitTest -P /data/local/tmp/AVCUtilsUnitTest/
+```
+Alternatively, the test can also be run using atest command.
+
+```
+atest AVCUtilsUnitTest -- --enable-module-dynamic-download=true
+```
diff --git a/media/libstagefright/foundation/tests/Android.bp b/media/libstagefright/foundation/tests/Android.bp
index f2157c9..45e81e8 100644
--- a/media/libstagefright/foundation/tests/Android.bp
+++ b/media/libstagefright/foundation/tests/Android.bp
@@ -25,3 +25,31 @@
         "Utils_test.cpp",
     ],
 }
+
+cc_test {
+    name: "MetaDataBaseUnitTest",
+    gtest: true,
+
+    srcs: [
+        "MetaDataBaseUnitTest.cpp",
+    ],
+
+    shared_libs: [
+        "libutils",
+        "liblog",
+    ],
+
+    static_libs: [
+        "libstagefright",
+        "libstagefright_foundation",
+    ],
+
+    header_libs: [
+        "libmedia_headers",
+    ],
+
+    cflags: [
+        "-Werror",
+        "-Wall",
+    ],
+}
diff --git a/media/libstagefright/foundation/tests/MetaDataBaseUnitTest.cpp b/media/libstagefright/foundation/tests/MetaDataBaseUnitTest.cpp
new file mode 100644
index 0000000..0aed4d2
--- /dev/null
+++ b/media/libstagefright/foundation/tests/MetaDataBaseUnitTest.cpp
@@ -0,0 +1,288 @@
+/*
+ * 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.
+ */
+#include <gtest/gtest.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <fstream>
+
+#include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/MetaDataBase.h>
+
+constexpr int32_t kWidth1 = 1920;
+constexpr int32_t kHeight1 = 1080;
+constexpr int32_t kWidth2 = 1280;
+constexpr int32_t kHeight2 = 920;
+constexpr int32_t kWidth3 = 720;
+constexpr int32_t kHeight3 = 480;
+constexpr int32_t kProfile = 1;
+constexpr int32_t kLevel = 1;
+constexpr int32_t kPlatformValue = 1;
+
+// Rectangle margins
+constexpr int32_t kLeft = 100;
+constexpr int32_t kTop = 100;
+constexpr int32_t kRight = 100;
+constexpr int32_t kBottom = 100;
+
+constexpr int64_t kDurationUs = 60000000;
+
+constexpr float kCaptureRate = 30.0;
+
+namespace android {
+
+class MetaDataBaseUnitTest : public ::testing::Test {};
+
+TEST_F(MetaDataBaseUnitTest, CreateMetaDataBaseTest) {
+    MetaDataBase *metaData = new MetaDataBase();
+    ASSERT_NE(metaData, nullptr) << "Failed to create meta data";
+
+    // Testing copy constructor
+    MetaDataBase *metaDataCopy = metaData;
+    ASSERT_NE(metaDataCopy, nullptr) << "Failed to create meta data copy";
+
+    delete metaData;
+}
+
+TEST_F(MetaDataBaseUnitTest, SetAndFindDataTest) {
+    MetaDataBase *metaData = new MetaDataBase();
+    ASSERT_NE(metaData, nullptr) << "Failed to create meta data";
+
+    // Setting the different key-value pair type for first time, overwrite
+    // expected to be false
+    bool status = metaData->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_AVC);
+    ASSERT_FALSE(status) << "Initializing kKeyMIMEType, overwrite is expected to be false";
+
+    status = metaData->setInt32(kKeyWidth, kWidth1);
+    ASSERT_FALSE(status) << "Initializing kKeyWidth, overwrite is expected to be false";
+    status = metaData->setInt32(kKeyHeight, kHeight1);
+    ASSERT_FALSE(status) << "Initializing kKeyHeight, overwrite is expected to be false";
+    status = metaData->setInt32(kKeyVideoProfile, kProfile);
+    ASSERT_FALSE(status) << "Initializing kKeyVideoProfile, overwrite is expected to be false";
+    status = metaData->setInt32(kKeyVideoLevel, kLevel);
+    ASSERT_FALSE(status) << "Initializing kKeyVideoLevel, overwrite is expected to be false";
+
+    status = metaData->setInt64(kKeyDuration, kDurationUs);
+    ASSERT_FALSE(status) << "Initializing kKeyDuration, overwrite is expected to be false";
+
+    status = metaData->setFloat(kKeyCaptureFramerate, kCaptureRate);
+    ASSERT_FALSE(status) << "Initializing kKeyCaptureFramerate, overwrite is expected to be false";
+
+    const int32_t *platform = &kPlatformValue;
+    status = metaData->setPointer(kKeyPlatformPrivate, (void *)platform);
+    ASSERT_FALSE(status) << "Initializing kKeyPlatformPrivate, overwrite is expected to be false";
+
+    status = metaData->setRect(kKeyCropRect, kLeft, kTop, kRight, kBottom);
+    ASSERT_FALSE(status) << "Initializing kKeyCropRect, overwrite is expected to be false";
+
+    // Dump to log for reference
+    metaData->dumpToLog();
+
+    // Find the data which was set
+    const char *mime;
+    status = metaData->findCString(kKeyMIMEType, &mime);
+    ASSERT_TRUE(status) << "kKeyMIMEType key does not exists in metadata";
+    ASSERT_STREQ(mime, MEDIA_MIMETYPE_VIDEO_AVC) << "Incorrect mime type returned";
+
+    int32_t width, height, profile, level;
+    status = metaData->findInt32(kKeyWidth, &width);
+    ASSERT_TRUE(status) << "kKeyWidth key does not exists in metadata";
+    ASSERT_EQ(width, kWidth1) << "Incorrect value of width returned";
+
+    status = metaData->findInt32(kKeyHeight, &height);
+    ASSERT_TRUE(status) << "kKeyHeight key does not exists in metadata";
+    ASSERT_EQ(height, kHeight1) << "Incorrect value of height returned";
+
+    status = metaData->findInt32(kKeyVideoProfile, &profile);
+    ASSERT_TRUE(status) << "kKeyVideoProfile key does not exists in metadata";
+    ASSERT_EQ(profile, kProfile) << "Incorrect value of profile returned";
+
+    status = metaData->findInt32(kKeyVideoLevel, &level);
+    ASSERT_TRUE(status) << "kKeyVideoLevel key does not exists in metadata";
+    ASSERT_EQ(level, kLevel) << "Incorrect value of level returned";
+
+    int64_t duration;
+    status = metaData->findInt64(kKeyDuration, &duration);
+    ASSERT_TRUE(status) << "kKeyDuration key does not exists in metadata";
+    ASSERT_EQ(duration, kDurationUs) << "Incorrect value of duration returned";
+
+    float frameRate;
+    status = metaData->findFloat(kKeyCaptureFramerate, &frameRate);
+    ASSERT_TRUE(status) << "kKeyCaptureFramerate key does not exists in metadata";
+    ASSERT_EQ(frameRate, kCaptureRate) << "Incorrect value of captureFrameRate returned";
+
+    int32_t top, bottom, left, right;
+    status = metaData->findRect(kKeyCropRect, &left, &top, &right, &bottom);
+    ASSERT_TRUE(status) << "kKeyCropRect key does not exists in metadata";
+    ASSERT_EQ(left, kLeft) << "Incorrect value of left margin returned";
+    ASSERT_EQ(top, kTop) << "Incorrect value of top margin returned";
+    ASSERT_EQ(right, kRight) << "Incorrect value of right margin returned";
+    ASSERT_EQ(bottom, kBottom) << "Incorrect value of bottom margin returned";
+
+    void *platformValue;
+    status = metaData->findPointer(kKeyPlatformPrivate, &platformValue);
+    ASSERT_TRUE(status) << "kKeyPlatformPrivate key does not exists in metadata";
+    ASSERT_EQ(platformValue, &kPlatformValue) << "Incorrect value of pointer returned";
+
+    // Check for the key which is not added to metadata
+    int32_t angle;
+    status = metaData->findInt32(kKeyRotation, &angle);
+    ASSERT_FALSE(status) << "Value for an invalid key is returned when the key is not set";
+
+    delete (metaData);
+}
+
+TEST_F(MetaDataBaseUnitTest, OverWriteFunctionalityTest) {
+    MetaDataBase *metaData = new MetaDataBase();
+    ASSERT_NE(metaData, nullptr) << "Failed to create meta data";
+
+    // set/set/read to check first overwrite operation
+    bool status = metaData->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_AVC);
+    ASSERT_FALSE(status) << "Initializing kKeyMIMEType, overwrite is expected to be false";
+    // Overwrite the value
+    status = metaData->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_HEVC);
+    ASSERT_TRUE(status) << "Setting kKeyMIMEType again, overwrite is expected to be true";
+    // Check the value
+    const char *mime;
+    status = metaData->findCString(kKeyMIMEType, &mime);
+    ASSERT_TRUE(status) << "kKeyMIMEType key does not exists in metadata";
+    ASSERT_STREQ(mime, MEDIA_MIMETYPE_VIDEO_HEVC) << "Mime value is not overwritten";
+
+    // set/set/set/read to check second overwrite operation
+    status = metaData->setInt32(kKeyWidth, kWidth1);
+    ASSERT_FALSE(status) << "Initializing kKeyWidth, overwrite is expected to be false";
+    status = metaData->setInt32(kKeyHeight, kHeight1);
+    ASSERT_FALSE(status) << "Initializing kKeyHeight, overwrite is expected to be false";
+    // Overwrite the value
+    status = metaData->setInt32(kKeyWidth, kWidth2);
+    ASSERT_TRUE(status) << "Setting kKeyWidth again, overwrite is expected to be true";
+    status = metaData->setInt32(kKeyHeight, kHeight2);
+    ASSERT_TRUE(status) << "Setting kKeyHeight again, overwrite is expected to be true";
+    // Overwrite the value again
+    status = metaData->setInt32(kKeyWidth, kWidth3);
+    ASSERT_TRUE(status) << "Setting kKeyWidth again, overwrite is expected to be true";
+    status = metaData->setInt32(kKeyHeight, kHeight3);
+    ASSERT_TRUE(status) << "Setting kKeyHeight again, overwrite is expected to be true";
+    // Check the value
+    int32_t width, height;
+    status = metaData->findInt32(kKeyWidth, &width);
+    ASSERT_TRUE(status) << "kKeyWidth key does not exists in metadata";
+    ASSERT_EQ(width, kWidth3) << "Value of width is not overwritten";
+
+    status = metaData->findInt32(kKeyHeight, &height);
+    ASSERT_TRUE(status) << "kKeyHeight key does not exists in metadata";
+    ASSERT_EQ(height, kHeight3) << "Value of height is not overwritten";
+
+    delete (metaData);
+}
+
+TEST_F(MetaDataBaseUnitTest, RemoveKeyTest) {
+    MetaDataBase *metaData = new MetaDataBase();
+    ASSERT_NE(metaData, nullptr) << "Failed to create meta data";
+
+    bool status = metaData->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_AVC);
+    ASSERT_FALSE(status) << "Initializing kKeyMIMEType, overwrite is expected to be false";
+    // Query the key
+    status = metaData->hasData(kKeyMIMEType);
+    ASSERT_TRUE(status) << "MetaData does not have the mime key";
+
+    status = metaData->remove(kKeyMIMEType);
+    ASSERT_TRUE(status) << "Failed to remove the kKeyMIMEType key";
+
+    // Query the key
+    status = metaData->hasData(kKeyMIMEType);
+    ASSERT_FALSE(status) << "MetaData has mime key after removing it, expected to be false";
+
+    // Remove the non existing key
+    status = metaData->remove(kKeyMIMEType);
+    ASSERT_FALSE(status) << "Removed the non existing key";
+
+    // Check overwriting the removed key
+    metaData->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_HEVC);
+    ASSERT_FALSE(status) << "Overwrite should be false since the key was removed";
+
+    status = metaData->setInt32(kKeyWidth, kWidth1);
+    ASSERT_FALSE(status) << "Initializing kKeyWidth, overwrite is expected to be false";
+
+    // Clear whole metadata
+    metaData->clear();
+
+    // Check finding key after clearing the metadata
+    int32_t width;
+    status = metaData->findInt32(kKeyWidth, &width);
+    ASSERT_FALSE(status) << "MetaData found kKeyWidth key after clearing all the items in it, "
+                            "expected to be false";
+
+    // Query the key
+    status = metaData->hasData(kKeyWidth);
+    ASSERT_FALSE(status)
+            << "MetaData has width key after clearing all the items in it, expected to be false";
+
+    status = metaData->hasData(kKeyMIMEType);
+    ASSERT_FALSE(status)
+            << "MetaData has mime key after clearing all the items in it, expected to be false";
+
+    // Check removing key after clearing the metadata
+    status = metaData->remove(kKeyMIMEType);
+    ASSERT_FALSE(status) << "Removed the key, after clearing the metadata";
+
+    // Checking set after clearing the metadata
+    status = metaData->setInt32(kKeyWidth, kWidth1);
+    ASSERT_FALSE(status) << "Overwrite should be false since the metadata was cleared";
+
+    metaData->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_HEVC);
+    ASSERT_FALSE(status) << "Overwrite should be false since the metadata was cleared";
+
+    delete (metaData);
+}
+
+TEST_F(MetaDataBaseUnitTest, ConvertToStringTest) {
+    MetaDataBase *metaData = new MetaDataBase();
+    ASSERT_NE(metaData, nullptr) << "Failed to create meta data";
+
+    String8 info = metaData->toString();
+    ASSERT_EQ(info.length(), 0) << "Empty MetaData length is non-zero: " << info.length();
+
+    bool status = metaData->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_AVC);
+    ASSERT_FALSE(status) << "Initializing kKeyMIMEType, overwrite is expected to be false";
+
+    status = metaData->setInt32(kKeyWidth, kWidth1);
+    ASSERT_FALSE(status) << "Initializing kKeyWidth, overwrite is expected to be false";
+    status = metaData->setInt32(kKeyHeight, kHeight1);
+    ASSERT_FALSE(status) << "Initializing kKeyHeight, overwrite is expected to be false";
+    status = metaData->setInt32(kKeyVideoProfile, kProfile);
+    ASSERT_FALSE(status) << "Initializing kKeyVideoProfile, overwrite is expected to be false";
+    status = metaData->setInt32(kKeyVideoLevel, kLevel);
+    ASSERT_FALSE(status) << "Initializing kKeyVideoLevel, overwrite is expected to be false";
+
+    info = metaData->toString();
+    ASSERT_GT(info.length(), 0) << "MetaData contains no information";
+
+    // Dump to log for reference
+    metaData->dumpToLog();
+
+    // Clear whole metadata
+    metaData->clear();
+
+    info = metaData->toString();
+    ASSERT_EQ(info.length(), 0) << "MetaData length is non-zero after clearing it: "
+                                << info.length();
+
+    delete (metaData);
+}
+
+}  // namespace android
diff --git a/media/libstagefright/foundation/tests/OpusHeader/Android.bp b/media/libstagefright/foundation/tests/OpusHeader/Android.bp
new file mode 100644
index 0000000..c1251a8
--- /dev/null
+++ b/media/libstagefright/foundation/tests/OpusHeader/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: "OpusHeaderTest",
+    gtest: true,
+
+    srcs: [
+        "OpusHeaderTest.cpp",
+    ],
+
+    shared_libs: [
+        "liblog",
+    ],
+
+    static_libs: [
+        "libstagefright_foundation",
+    ],
+
+    cflags: [
+        "-Werror",
+        "-Wall",
+    ],
+
+    sanitize: {
+        misc_undefined: [
+            "unsigned-integer-overflow",
+            "signed-integer-overflow",
+        ],
+        cfi: true,
+    },
+}
diff --git a/media/libstagefright/foundation/tests/OpusHeader/AndroidTest.xml b/media/libstagefright/foundation/tests/OpusHeader/AndroidTest.xml
new file mode 100644
index 0000000..afee16a
--- /dev/null
+++ b/media/libstagefright/foundation/tests/OpusHeader/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 opus header unit tests">
+    <option name="test-suite-tag" value="OpusHeaderTest" />
+    <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+        <option name="cleanup" value="true" />
+        <option name="push" value="OpusHeaderTest->/data/local/tmp/OpusHeaderTest" />
+        <option name="push-file"
+            key="https://storage.googleapis.com/android_media/frameworks/av/media/libstagefright/foundation/tests/OpusHeader/OpusHeader.zip?unzip=true"
+            value="/data/local/tmp/OpusHeaderTestRes/" />
+    </target_preparer>
+
+    <test class="com.android.tradefed.testtype.GTest" >
+        <option name="native-test-device-path" value="/data/local/tmp" />
+        <option name="module-name" value="OpusHeaderTest" />
+        <option name="native-test-flag" value="-P /data/local/tmp/OpusHeaderTestRes/" />
+    </test>
+</configuration>
\ No newline at end of file
diff --git a/media/libstagefright/foundation/tests/OpusHeader/OpusHeaderTest.cpp b/media/libstagefright/foundation/tests/OpusHeader/OpusHeaderTest.cpp
new file mode 100644
index 0000000..e39c915
--- /dev/null
+++ b/media/libstagefright/foundation/tests/OpusHeader/OpusHeaderTest.cpp
@@ -0,0 +1,342 @@
+/*
+ * 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 "OpusHeaderTest"
+#include <utils/Log.h>
+
+#include <fstream>
+#include <stdio.h>
+#include <string.h>
+
+#include <media/stagefright/foundation/OpusHeader.h>
+
+#include "OpusHeaderTestEnvironment.h"
+
+using namespace android;
+
+#define OUTPUT_FILE_NAME "/data/local/tmp/OpusOutput"
+
+// Opus in WebM is a well-known, yet under-documented, format. The codec private data
+// of the track is an Opus Ogg header (https://tools.ietf.org/html/rfc7845#section-5.1)
+// channel mapping offset in opus header
+constexpr size_t kOpusHeaderStreamMapOffset = 21;
+constexpr size_t kMaxOpusHeaderSize = 100;
+// AOPUSHDR + AOPUSHDRLength +
+// (8 + 8 ) +
+// Header(csd) + num_streams + num_coupled + 1
+// (19 + 1 + 1 + 1) +
+// AOPUSDLY + AOPUSDLYLength + DELAY + AOPUSPRL + AOPUSPRLLength + PRL
+// (8 + 8 + 8 + 8 + 8 + 8)
+// = 86
+constexpr size_t kOpusHeaderChannelMapOffset = 86;
+constexpr uint32_t kOpusSampleRate = 48000;
+constexpr uint64_t kOpusSeekPrerollNs = 80000000;
+constexpr int64_t kNsecPerSec = 1000000000ll;
+
+// Opus uses Vorbis channel mapping, and Vorbis channel mapping specifies
+// mappings for up to 8 channels. This information is part of the Vorbis I
+// Specification:
+// http://www.xiph.org/vorbis/doc/Vorbis_I_spec.html
+constexpr int kMaxChannels = 8;
+constexpr uint8_t kOpusChannelMap[kMaxChannels][kMaxChannels] = {
+        {0},
+        {0, 1},
+        {0, 2, 1},
+        {0, 1, 2, 3},
+        {0, 4, 1, 2, 3},
+        {0, 4, 1, 2, 3, 5},
+        {0, 4, 1, 2, 3, 5, 6},
+        {0, 6, 1, 2, 3, 4, 5, 7},
+};
+
+static OpusHeaderTestEnvironment *gEnv = nullptr;
+
+class OpusHeaderTest {
+  public:
+    OpusHeaderTest() : mInputBuffer(nullptr) {}
+
+    ~OpusHeaderTest() {
+        if (mEleStream.is_open()) mEleStream.close();
+        if (mInputBuffer) {
+            free(mInputBuffer);
+            mInputBuffer = nullptr;
+        }
+    }
+    ifstream mEleStream;
+    uint8_t *mInputBuffer;
+};
+
+class OpusHeaderParseTest : public OpusHeaderTest,
+                            public ::testing::TestWithParam<
+                                    tuple<string /* InputFileName */, int32_t /* ChannelCount */,
+                                          bool /* isHeaderValid */, bool /* isCodecDelayValid */,
+                                          bool /* isSeekPreRollValid */, bool /* isInputValid */>> {
+};
+
+class OpusHeaderWriteTest
+    : public OpusHeaderTest,
+      public ::testing::TestWithParam<tuple<int32_t /* ChannelCount */, int32_t /* skipSamples */,
+                                            string /* referenceFile */>> {};
+
+TEST_P(OpusHeaderWriteTest, WriteTest) {
+    tuple<int32_t, int32_t, string> params = GetParam();
+    OpusHeader writtenHeader;
+    memset(&writtenHeader, 0, sizeof(writtenHeader));
+    int32_t channels = get<0>(params);
+    writtenHeader.channels = channels;
+    writtenHeader.num_streams = channels;
+    writtenHeader.channel_mapping = ((channels > 8) ? 255 : (channels > 2));
+    int32_t skipSamples = get<1>(params);
+    string referenceFileName = gEnv->getRes() + get<2>(params);
+    writtenHeader.skip_samples = skipSamples;
+    uint64_t codecDelayNs = skipSamples * kNsecPerSec / kOpusSampleRate;
+    uint8_t headerData[kMaxOpusHeaderSize];
+    int32_t headerSize = WriteOpusHeaders(writtenHeader, kOpusSampleRate, headerData,
+                                          sizeof(headerData), codecDelayNs, kOpusSeekPrerollNs);
+    ASSERT_GT(headerSize, 0) << "failed to generate Opus header";
+    ASSERT_LE(headerSize, kMaxOpusHeaderSize)
+            << "Invalid header written. Header size can't exceed kMaxOpusHeaderSize";
+
+    ofstream ostrm;
+    ostrm.open(OUTPUT_FILE_NAME, ofstream::binary);
+    ASSERT_TRUE(ostrm.is_open()) << "Failed to open output file " << OUTPUT_FILE_NAME;
+    ostrm.write(reinterpret_cast<char *>(headerData), headerSize);
+    ostrm.close();
+
+    mEleStream.open(referenceFileName, ifstream::binary);
+    ASSERT_EQ(mEleStream.is_open(), true) << "Failed to open referenceFileName " << get<2>(params);
+
+    struct stat buf;
+    int32_t statStatus = stat(referenceFileName.c_str(), &buf);
+    ASSERT_EQ(statStatus, 0) << "Unable to get file properties";
+
+    size_t fileSize = buf.st_size;
+    mInputBuffer = (uint8_t *)malloc(fileSize);
+    ASSERT_NE(mInputBuffer, nullptr) << "Insufficient memory. Malloc failed for size " << fileSize;
+
+    mEleStream.read(reinterpret_cast<char *>(mInputBuffer), fileSize);
+    ASSERT_EQ(mEleStream.gcount(), fileSize) << "mEleStream.gcount() != bytesCount";
+
+    ASSERT_EQ(fileSize, headerSize)
+            << "Mismatch in size between header generated and reference header";
+    int32_t match = memcmp(reinterpret_cast<char *>(mInputBuffer),
+                           reinterpret_cast<char *>(headerData), fileSize);
+    ASSERT_EQ(match, 0) << "Opus header does not match reference file: " << referenceFileName;
+
+    size_t opusHeadSize = 0;
+    size_t codecDelayBufSize = 0;
+    size_t seekPreRollBufSize = 0;
+    void *opusHeadBuf = nullptr;
+    void *codecDelayBuf = nullptr;
+    void *seekPreRollBuf = nullptr;
+    bool status = GetOpusHeaderBuffers(headerData, headerSize, &opusHeadBuf, &opusHeadSize,
+                                       &codecDelayBuf, &codecDelayBufSize, &seekPreRollBuf,
+                                       &seekPreRollBufSize);
+    ASSERT_TRUE(status) << "Encountered error in GetOpusHeaderBuffers";
+
+    uint64_t value = *((uint64_t *)codecDelayBuf);
+    ASSERT_EQ(value, codecDelayNs);
+
+    value = *((uint64_t *)seekPreRollBuf);
+    ASSERT_EQ(value, kOpusSeekPrerollNs);
+
+    OpusHeader parsedHeader;
+    status = ParseOpusHeader((uint8_t *)opusHeadBuf, opusHeadSize, &parsedHeader);
+    ASSERT_TRUE(status) << "Encountered error while Parsing Opus Header.";
+
+    ASSERT_EQ(writtenHeader.channels, parsedHeader.channels)
+            << "Invalid header generated. Mismatch between channel counts";
+
+    ASSERT_EQ(writtenHeader.skip_samples, parsedHeader.skip_samples)
+            << "Mismatch between no of skipSamples written "
+               "and no of skipSamples got after parsing";
+
+    ASSERT_EQ(writtenHeader.channel_mapping, parsedHeader.channel_mapping)
+            << "Mismatch between channelMapping written "
+               "and channelMapping got after parsing";
+
+    if (parsedHeader.channel_mapping) {
+        ASSERT_GT(parsedHeader.channels, 2);
+        ASSERT_EQ(writtenHeader.num_streams, parsedHeader.num_streams)
+                << "Invalid header generated. Mismatch between channel counts";
+
+        ASSERT_EQ(writtenHeader.num_coupled, parsedHeader.num_coupled)
+                << "Invalid header generated. Mismatch between channel counts";
+
+        ASSERT_EQ(parsedHeader.num_coupled + parsedHeader.num_streams, parsedHeader.channels);
+
+        ASSERT_LE(parsedHeader.num_coupled, parsedHeader.num_streams)
+                << "Invalid header generated. Number of coupled streams cannot be greater than "
+                   "number "
+                   "of streams.";
+
+        ASSERT_EQ(headerSize, kOpusHeaderChannelMapOffset + writtenHeader.channels)
+                << "Invalid header written. Header size should be equal to 86 + "
+                   "writtenHeader.channels";
+
+        uint8_t mappedChannelNumber;
+        for (int32_t channelNumber = 0; channelNumber < channels; channelNumber++) {
+            mappedChannelNumber = *(reinterpret_cast<uint8_t *>(opusHeadBuf) +
+                                    kOpusHeaderStreamMapOffset + channelNumber);
+            ASSERT_LT(mappedChannelNumber, channels) << "Invalid header generated. Channel mapping "
+                                                        "cannot be greater than channel count.";
+
+            ASSERT_EQ(mappedChannelNumber, kOpusChannelMap[channels - 1][channelNumber])
+                    << "Invalid header generated. Channel mapping is not as per specification.";
+        }
+    } else {
+        ASSERT_LE(parsedHeader.channels, 2);
+    }
+}
+
+TEST_P(OpusHeaderParseTest, ParseTest) {
+    tuple<string, int32_t, bool, bool, bool, bool> params = GetParam();
+    string inputFileName = gEnv->getRes() + get<0>(params);
+    mEleStream.open(inputFileName, ifstream::binary);
+    ASSERT_EQ(mEleStream.is_open(), true) << "Failed to open inputfile " << get<0>(params);
+    bool isHeaderValid = get<2>(params);
+    bool isCodecDelayValid = get<3>(params);
+    bool isSeekPreRollValid = get<4>(params);
+    bool isInputValid = get<5>(params);
+
+    struct stat buf;
+    stat(inputFileName.c_str(), &buf);
+    size_t fileSize = buf.st_size;
+    mInputBuffer = (uint8_t *)malloc(fileSize);
+    ASSERT_NE(mInputBuffer, nullptr) << "Insufficient memory. Malloc failed for size " << fileSize;
+
+    mEleStream.read(reinterpret_cast<char *>(mInputBuffer), fileSize);
+    ASSERT_EQ(mEleStream.gcount(), fileSize) << "mEleStream.gcount() != bytesCount";
+
+    OpusHeader header;
+    size_t opusHeadSize = 0;
+    size_t codecDelayBufSize = 0;
+    size_t seekPreRollBufSize = 0;
+    void *opusHeadBuf = nullptr;
+    void *codecDelayBuf = nullptr;
+    void *seekPreRollBuf = nullptr;
+    bool status = GetOpusHeaderBuffers(mInputBuffer, fileSize, &opusHeadBuf, &opusHeadSize,
+                                       &codecDelayBuf, &codecDelayBufSize, &seekPreRollBuf,
+                                       &seekPreRollBufSize);
+    if (!isHeaderValid) {
+        ASSERT_EQ(opusHeadBuf, nullptr);
+    } else {
+        ASSERT_NE(opusHeadBuf, nullptr);
+    }
+    if (!isCodecDelayValid) {
+        ASSERT_EQ(codecDelayBuf, nullptr);
+    } else {
+        ASSERT_NE(codecDelayBuf, nullptr);
+    }
+    if (!isSeekPreRollValid) {
+        ASSERT_EQ(seekPreRollBuf, nullptr);
+    } else {
+        ASSERT_NE(seekPreRollBuf, nullptr);
+    }
+    if (!status) {
+        ASSERT_FALSE(isInputValid) << "GetOpusHeaderBuffers failed";
+        return;
+    }
+
+    status = ParseOpusHeader((uint8_t *)opusHeadBuf, opusHeadSize, &header);
+
+    if (status) {
+        ASSERT_TRUE(isInputValid) << "Parse opus header didn't fail for invalid input";
+    } else {
+        ASSERT_FALSE(isInputValid);
+        return;
+    }
+
+    int32_t channels = get<1>(params);
+    ASSERT_EQ(header.channels, channels) << "Parser returned invalid channel count";
+    ASSERT_LE(header.channels, kMaxChannels);
+
+    ASSERT_LE(header.num_coupled, header.num_streams)
+            << "Invalid header generated. Number of coupled streams cannot be greater than number "
+               "of streams.";
+
+    ASSERT_EQ(header.num_coupled + header.num_streams, header.channels);
+
+    if (header.channel_mapping) {
+        uint8_t mappedChannelNumber;
+        for (int32_t channelNumber = 0; channelNumber < channels; channelNumber++) {
+            mappedChannelNumber = *(reinterpret_cast<uint8_t *>(opusHeadBuf) +
+                                    kOpusHeaderStreamMapOffset + channelNumber);
+            ASSERT_LT(mappedChannelNumber, channels)
+                    << "Invalid header. Channel mapping cannot be greater than channel count.";
+
+            ASSERT_EQ(mappedChannelNumber, kOpusChannelMap[channels - 1][channelNumber])
+                    << "Invalid header generated. Channel mapping "
+                       "is not as per specification.";
+        }
+    }
+}
+
+INSTANTIATE_TEST_SUITE_P(
+        OpusHeaderTestAll, OpusHeaderWriteTest,
+        ::testing::Values(make_tuple(1, 312, "output_channels_1skipSamples_312.opus"),
+                          make_tuple(2, 312, "output_channels_2skipSamples_312.opus"),
+                          make_tuple(5, 312, "output_channels_5skipSamples_312.opus"),
+                          make_tuple(6, 312, "output_channels_6skipSamples_312.opus"),
+                          make_tuple(1, 0, "output_channels_1skipSamples_0.opus"),
+                          make_tuple(2, 0, "output_channels_2skipSamples_0.opus"),
+                          make_tuple(5, 0, "output_channels_5skipSamples_0.opus"),
+                          make_tuple(6, 0, "output_channels_6skipSamples_0.opus"),
+                          make_tuple(1, 624, "output_channels_1skipSamples_624.opus"),
+                          make_tuple(2, 624, "output_channels_2skipSamples_624.opus"),
+                          make_tuple(5, 624, "output_channels_5skipSamples_624.opus"),
+                          make_tuple(6, 624, "output_channels_6skipSamples_624.opus")));
+
+INSTANTIATE_TEST_SUITE_P(
+        OpusHeaderTestAll, OpusHeaderParseTest,
+        ::testing::Values(
+                make_tuple("2ch_valid_size83B.opus", 2, true, true, true, true),
+                make_tuple("3ch_valid_size88B.opus", 3, true, true, true, true),
+                make_tuple("5ch_valid.opus", 5, true, false, false, true),
+                make_tuple("6ch_valid.opus", 6, true, false, false, true),
+                make_tuple("1ch_valid.opus", 1, true, false, false, true),
+                make_tuple("2ch_valid.opus", 2, true, false, false, true),
+                make_tuple("3ch_invalid_size.opus", 3, true, true, true, false),
+                make_tuple("3ch_invalid_streams.opus", 3, true, true, true, false),
+                make_tuple("5ch_invalid_channelmapping.opus", 5, true, false, false, false),
+                make_tuple("5ch_invalid_coupledstreams.opus", 5, true, false, false, false),
+                make_tuple("6ch_invalid_channelmapping.opus", 6, true, false, false, false),
+                make_tuple("9ch_invalid_channels.opus", 9, true, true, true, false),
+                make_tuple("2ch_invalid_header.opus", 2, false, false, false, false),
+                make_tuple("2ch_invalid_headerlength_16.opus", 2, false, false, false, false),
+                make_tuple("2ch_invalid_headerlength_256.opus", 2, false, false, false, false),
+                make_tuple("2ch_invalid_size.opus", 2, false, false, false, false),
+                make_tuple("3ch_invalid_channelmapping_0.opus", 3, true, true, true, false),
+                make_tuple("3ch_invalid_coupledstreams.opus", 3, true, true, true, false),
+                make_tuple("3ch_invalid_headerlength.opus", 3, true, true, true, false),
+                make_tuple("3ch_invalid_headerSize1.opus", 3, false, false, false, false),
+                make_tuple("3ch_invalid_headerSize2.opus", 3, false, false, false, false),
+                make_tuple("3ch_invalid_headerSize3.opus", 3, false, false, false, false),
+                make_tuple("3ch_invalid_nodelay.opus", 3, false, false, false, false),
+                make_tuple("3ch_invalid_nopreroll.opus", 3, false, false, false, false)));
+
+int main(int argc, char **argv) {
+    gEnv = new OpusHeaderTestEnvironment();
+    ::testing::AddGlobalTestEnvironment(gEnv);
+    ::testing::InitGoogleTest(&argc, argv);
+    int status = gEnv->initFromOptions(argc, argv);
+    if (status == 0) {
+        status = RUN_ALL_TESTS();
+        ALOGD("Opus Header Test Result = %d\n", status);
+    }
+    return status;
+}
diff --git a/media/libstagefright/foundation/tests/OpusHeader/OpusHeaderTestEnvironment.h b/media/libstagefright/foundation/tests/OpusHeader/OpusHeaderTestEnvironment.h
new file mode 100644
index 0000000..d0163c3
--- /dev/null
+++ b/media/libstagefright/foundation/tests/OpusHeader/OpusHeaderTestEnvironment.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 __OPUS_HEADER_TEST_ENVIRONMENT_H__
+#define __OPUS_HEADER_TEST_ENVIRONMENT_H__
+
+#include <gtest/gtest.h>
+
+#include <getopt.h>
+
+using namespace std;
+
+class OpusHeaderTestEnvironment : public ::testing::Environment {
+  public:
+    OpusHeaderTestEnvironment() : 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 OpusHeaderTestEnvironment::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  // __OPUS_HEADER_TEST_ENVIRONMENT_H__
diff --git a/media/libstagefright/foundation/tests/OpusHeader/README.md b/media/libstagefright/foundation/tests/OpusHeader/README.md
new file mode 100644
index 0000000..860c827
--- /dev/null
+++ b/media/libstagefright/foundation/tests/OpusHeader/README.md
@@ -0,0 +1,39 @@
+## Media Testing ##
+---
+#### Opus Header
+The OpusHeader Test Suite validates the OPUS header available in libstagefright.
+
+Run the following steps to build the test suite:
+```
+m OpusHeaderTest
+```
+
+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/OpusHeaderTest/OpusHeaderTest /data/local/tmp/
+```
+
+To test 32-bit binary push binaries from nativetest.
+```
+adb push ${OUT}/data/nativetest/OpusHeaderTest/OpusHeaderTest /data/local/tmp/
+```
+
+The resource file for the tests is taken from [here](https://storage.googleapis.com/android_media/frameworks/av/media/libstagefright/foundation/tests/OpusHeader/OpusHeader.zip). Download, unzip and push these files into device for testing.
+
+```
+adb push OpusHeader /data/local/tmp/
+```
+
+usage: OpusHeaderTest -P \<path_to_folder\>
+```
+adb shell /data/local/tmp/OpusHeaderTest -P /data/local/tmp/OpusHeader/
+```
+Alternatively, the test can also be run using atest command.
+
+```
+atest OpusHeaderTest -- --enable-module-dynamic-download=true
+```
diff --git a/media/libstagefright/mpeg2ts/test/Android.bp b/media/libstagefright/mpeg2ts/test/Android.bp
new file mode 100644
index 0000000..4e4832a
--- /dev/null
+++ b/media/libstagefright/mpeg2ts/test/Android.bp
@@ -0,0 +1,70 @@
+/*
+ * 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: "Mpeg2tsUnitTest",
+    gtest: true,
+
+    srcs: [
+        "Mpeg2tsUnitTest.cpp"
+    ],
+
+    shared_libs: [
+        "android.hardware.cas@1.0",
+        "android.hardware.cas.native@1.0",
+        "android.hidl.token@1.0-utils",
+        "android.hidl.allocator@1.0",
+        "libcrypto",
+        "libhidlbase",
+        "libhidlmemory",
+        "liblog",
+        "libmedia",
+        "libbinder",
+        "libbinder_ndk",
+        "libutils",
+    ],
+
+    static_libs: [
+        "libdatasource",
+        "libstagefright",
+        "libstagefright_foundation",
+        "libstagefright_metadatautils",
+        "libstagefright_mpeg2support",
+    ],
+
+    include_dirs: [
+        "frameworks/av/media/extractors/",
+        "frameworks/av/media/libstagefright/",
+    ],
+
+    header_libs: [
+        "libmedia_headers",
+        "libaudioclient_headers",
+    ],
+
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
+
+    sanitize: {
+        cfi: true,
+        misc_undefined: [
+            "unsigned-integer-overflow",
+            "signed-integer-overflow",
+        ],
+    },
+}
diff --git a/media/libstagefright/mpeg2ts/test/AndroidTest.xml b/media/libstagefright/mpeg2ts/test/AndroidTest.xml
new file mode 100644
index 0000000..ac1294d
--- /dev/null
+++ b/media/libstagefright/mpeg2ts/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 Mpeg2ts unit tests">
+    <option name="test-suite-tag" value="Mpeg2tsUnitTest" />
+    <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+        <option name="cleanup" value="true" />
+        <option name="push" value="Mpeg2tsUnitTest->/data/local/tmp/Mpeg2tsUnitTest" />
+        <option name="push-file"
+            key="https://storage.googleapis.com/android_media/frameworks/av/media/libstagefright/mpeg2ts/test/Mpeg2tsUnitTest.zip?unzip=true"
+            value="/data/local/tmp/Mpeg2tsUnitTestRes/" />
+    </target_preparer>
+
+    <test class="com.android.tradefed.testtype.GTest" >
+        <option name="native-test-device-path" value="/data/local/tmp" />
+        <option name="module-name" value="Mpeg2tsUnitTest" />
+        <option name="native-test-flag" value="-P /data/local/tmp/Mpeg2tsUnitTestRes/" />
+    </test>
+</configuration>
diff --git a/media/libstagefright/mpeg2ts/test/Mpeg2tsUnitTest.cpp b/media/libstagefright/mpeg2ts/test/Mpeg2tsUnitTest.cpp
new file mode 100644
index 0000000..79c233b
--- /dev/null
+++ b/media/libstagefright/mpeg2ts/test/Mpeg2tsUnitTest.cpp
@@ -0,0 +1,236 @@
+/*
+ * 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 "Mpeg2tsUnitTest"
+
+#include <utils/Log.h>
+
+#include <stdint.h>
+#include <sys/stat.h>
+
+#include <datasource/FileSource.h>
+#include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/MetaDataBase.h>
+#include <media/stagefright/foundation/AUtils.h>
+
+#include "mpeg2ts/ATSParser.h"
+#include "mpeg2ts/AnotherPacketSource.h"
+
+#include "Mpeg2tsUnitTestEnvironment.h"
+
+constexpr size_t kTSPacketSize = 188;
+constexpr uint16_t kPIDMask = 0x1FFF;
+// Max value of PID which is also used for Null packets
+constexpr uint16_t kPIDMaxValue = 8191;
+constexpr uint8_t kTSSyncByte = 0x47;
+constexpr uint8_t kVideoPresent = 0x01;
+constexpr uint8_t kAudioPresent = 0x02;
+constexpr uint8_t kMetaDataPresent = 0x04;
+
+static Mpeg2tsUnitTestEnvironment *gEnv = nullptr;
+
+using namespace android;
+
+class Mpeg2tsUnitTest
+    : public ::testing ::TestWithParam<
+              tuple</*fileName*/ string, /*sourceType*/ char, /*numSource*/ uint16_t>> {
+  public:
+    Mpeg2tsUnitTest()
+        : mInputBuffer(nullptr), mSource(nullptr), mFpInput(nullptr), mParser(nullptr) {}
+
+    ~Mpeg2tsUnitTest() {
+        if (mInputBuffer) free(mInputBuffer);
+        if (mFpInput) fclose(mFpInput);
+        mSource.clear();
+    }
+
+    void SetUp() override {
+        mOffset = 0;
+        mNumDataSource = 0;
+        tuple<string, char, uint16_t> params = GetParam();
+        char sourceType = get<1>(params);
+        /* mSourceType = 0b x x x x x M A V
+                                     /  |  \
+                            metaData  audio  video */
+        mMediaType = (sourceType & 0x07);
+        mNumDataSource = get<2>(params);
+        string inputFile = gEnv->getRes() + get<0>(params);
+        mFpInput = fopen(inputFile.c_str(), "rb");
+        ASSERT_NE(mFpInput, nullptr) << "Failed to open file: " << inputFile;
+
+        struct stat buf;
+        int8_t err = stat(inputFile.c_str(), &buf);
+        ASSERT_EQ(err, 0) << "Failed to get information for file: " << inputFile;
+
+        long fileSize = buf.st_size;
+        mTotalPackets = fileSize / kTSPacketSize;
+        int32_t fd = fileno(mFpInput);
+        ASSERT_GE(fd, 0) << "Failed to get the integer file descriptor";
+
+        mSource = new FileSource(dup(fd), 0, buf.st_size);
+        ASSERT_NE(mSource, nullptr) << "Failed to get the data source!";
+
+        mParser = new ATSParser();
+        ASSERT_NE(mParser, nullptr) << "Unable to create ATS parser!";
+        mInputBuffer = (uint8_t *)malloc(kTSPacketSize);
+        ASSERT_NE(mInputBuffer, nullptr) << "Failed to allocate memory for TS packet!";
+    }
+
+    uint64_t mOffset;
+    uint64_t mTotalPackets;
+    uint16_t mNumDataSource;
+
+    int8_t mMediaType;
+
+    uint8_t *mInputBuffer;
+    string mInputFile;
+    sp<DataSource> mSource;
+    FILE *mFpInput;
+    ATSParser *mParser;
+};
+
+TEST_P(Mpeg2tsUnitTest, MediaInfoTest) {
+    bool videoFound = false;
+    bool audioFound = false;
+    bool metaDataFound = false;
+    bool syncPointPresent = false;
+
+    int16_t totalDataSource = 0;
+    int32_t val32 = 0;
+    uint8_t numDataSource = 0;
+    uint8_t packet[kTSPacketSize];
+    ssize_t numBytesRead = -1;
+
+    ATSParser::SyncEvent event(mOffset);
+    static const ATSParser::SourceType mediaType[] = {ATSParser::VIDEO, ATSParser::AUDIO,
+                                                      ATSParser::META, ATSParser::NUM_SOURCE_TYPES};
+    const uint32_t nMediaTypes = sizeof(mediaType) / sizeof(mediaType[0]);
+
+    while ((numBytesRead = mSource->readAt(mOffset, packet, kTSPacketSize)) == kTSPacketSize) {
+        ASSERT_TRUE(packet[0] == kTSSyncByte) << "Sync byte error!";
+
+        // pid is 13 bits
+        uint16_t pid = (packet[1] + (packet[2] << 8)) & kPIDMask;
+        ASSERT_TRUE(pid <= kPIDMaxValue) << "Invalid PID: " << pid;
+
+        status_t err = mParser->feedTSPacket(packet, kTSPacketSize, &event);
+        ASSERT_EQ(err, (status_t)OK) << "Unable to feed TS packet!";
+
+        mOffset += numBytesRead;
+        for (int i = 0; i < nMediaTypes; i++) {
+            if (mParser->hasSource(mediaType[i])) {
+                switch (mediaType[i]) {
+                    case ATSParser::VIDEO:
+                        videoFound = true;
+                        break;
+                    case ATSParser::AUDIO:
+                        audioFound = true;
+                        break;
+                    case ATSParser::META:
+                        metaDataFound = true;
+                        break;
+                    case ATSParser::NUM_SOURCE_TYPES:
+                        numDataSource = 3;
+                        break;
+                    default:
+                        break;
+                }
+            }
+        }
+        if (videoFound && audioFound && metaDataFound && (numDataSource == 3)) break;
+    }
+
+    for (int i = 0; i < nMediaTypes; i++) {
+        ATSParser::SourceType currentMediaType = mediaType[i];
+        if (mParser->hasSource(currentMediaType)) {
+            if (event.hasReturnedData()) {
+                syncPointPresent = true;
+                sp<AnotherPacketSource> syncPacketSource = event.getMediaSource();
+                ASSERT_NE(syncPacketSource, nullptr)
+                        << "Cannot get sync source for media type: " << currentMediaType;
+
+                status_t err = syncPacketSource->start();
+                ASSERT_EQ(err, (status_t)OK) << "Error returned while starting!";
+
+                sp<MetaData> format = syncPacketSource->getFormat();
+                ASSERT_NE(format, nullptr) << "Unable to get the format of the source packet!";
+
+                MediaBufferBase *buf;
+                syncPacketSource->read(&buf, nullptr);
+                ASSERT_NE(buf, nullptr) << "Failed to read sync packet source data";
+
+                MetaDataBase &inMeta = buf->meta_data();
+                bool status = inMeta.findInt32(kKeyIsSyncFrame, &val32);
+                ASSERT_EQ(status, true) << "Sync frame key is not set";
+
+                status = inMeta.findInt32(kKeyCryptoMode, &val32);
+                ASSERT_EQ(status, false) << "Invalid packet, found scrambled packets!";
+
+                err = syncPacketSource->stop();
+                ASSERT_EQ(err, (status_t)OK) << "Error returned while stopping!";
+            }
+            sp<AnotherPacketSource> packetSource = mParser->getSource(currentMediaType);
+            ASSERT_NE(packetSource, nullptr)
+                    << "Cannot get source for media type: " << currentMediaType;
+
+            status_t err = packetSource->start();
+            ASSERT_EQ(err, (status_t)OK) << "Error returned while starting!";
+            sp<MetaData> format = packetSource->getFormat();
+            ASSERT_NE(format, nullptr) << "Unable to get the format of the packet!";
+
+            err = packetSource->stop();
+            ASSERT_EQ(err, (status_t)OK) << "Error returned while stopping!";
+        }
+    }
+
+    ASSERT_EQ(videoFound, bool(mMediaType & kVideoPresent)) << "No Video packets found!";
+    ASSERT_EQ(audioFound, bool(mMediaType & kAudioPresent)) << "No Audio packets found!";
+    ASSERT_EQ(metaDataFound, bool(mMediaType & kMetaDataPresent)) << "No meta data found!";
+
+    if (videoFound || audioFound) {
+        ASSERT_TRUE(syncPointPresent) << "No sync points found for audio/video";
+    }
+
+    if (videoFound) totalDataSource += 1;
+    if (audioFound) totalDataSource += 1;
+    if (metaDataFound) totalDataSource += 1;
+
+    ASSERT_TRUE(totalDataSource == mNumDataSource)
+            << "Expected " << mNumDataSource << " data sources, found " << totalDataSource;
+    if (numDataSource == 3) {
+        ASSERT_EQ(numDataSource, mNumDataSource)
+                << "Expected " << mNumDataSource << " data sources, found " << totalDataSource;
+    }
+}
+
+INSTANTIATE_TEST_SUITE_P(
+        infoTest, Mpeg2tsUnitTest,
+        ::testing::Values(make_tuple("crowd_1920x1080_25fps_6700kbps_h264.ts", 0x01, 1),
+                          make_tuple("segment000001.ts", 0x03, 2),
+                          make_tuple("bbb_44100hz_2ch_128kbps_mp3_5mins.ts", 0x02, 1)));
+
+int32_t main(int argc, char **argv) {
+    gEnv = new Mpeg2tsUnitTestEnvironment();
+    ::testing::AddGlobalTestEnvironment(gEnv);
+    ::testing::InitGoogleTest(&argc, argv);
+    uint8_t status = gEnv->initFromOptions(argc, argv);
+    if (status == 0) {
+        status = RUN_ALL_TESTS();
+        ALOGV("Mpeg2tsUnit Test Result = %d\n", status);
+    }
+    return status;
+}
diff --git a/media/libstagefright/mpeg2ts/test/Mpeg2tsUnitTestEnvironment.h b/media/libstagefright/mpeg2ts/test/Mpeg2tsUnitTestEnvironment.h
new file mode 100644
index 0000000..9e41db7
--- /dev/null
+++ b/media/libstagefright/mpeg2ts/test/Mpeg2tsUnitTestEnvironment.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 __MPEG2TS_UNIT_TEST_ENVIRONMENT_H__
+#define __MPEG2TS_UNIT_TEST_ENVIRONMENT_H__
+
+#include <gtest/gtest.h>
+
+#include <getopt.h>
+
+using namespace std;
+
+class Mpeg2tsUnitTestEnvironment : public::testing::Environment {
+  public:
+    Mpeg2tsUnitTestEnvironment() : 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 Mpeg2tsUnitTestEnvironment::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  // __MPEG2TS_UNIT_TEST_ENVIRONMENT_H__
diff --git a/media/libstagefright/mpeg2ts/test/README.md b/media/libstagefright/mpeg2ts/test/README.md
new file mode 100644
index 0000000..237ce72
--- /dev/null
+++ b/media/libstagefright/mpeg2ts/test/README.md
@@ -0,0 +1,38 @@
+## Media Testing ##
+---
+#### Mpeg2TS Unit Test :
+The Mpeg2TS Unit Test Suite validates the functionality of the libraries present in Mpeg2TS.
+
+Run the following steps to build the test suite:
+```
+mmm frameworks/av/media/libstagefright/mpeg2ts/test/
+```
+
+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/Mpeg2tsUnitTest/Mpeg2tsUnitTest /data/local/tmp/
+
+To test 32-bit binary push binaries from nativetest.
+
+adb push ${OUT}/data/nativetest/Mpeg2tsUnitTest/Mpeg2tsUnitTest /data/local/tmp/
+
+The resource file for the tests is taken from [here](https://storage.googleapis.com/android_media/frameworks/av/media/libstagefright/mpeg2ts/test/Mpeg2tsUnitTest.zip ).
+Download, unzip and push these files into device for testing.
+
+```
+adb push Mpeg2tsUnitTestRes/. /data/local/tmp/
+```
+
+usage: Mpeg2tsUnitTest -P \<path_to_folder\>
+```
+adb shell /data/local/tmp/Mpeg2tsUnitTest -P /data/local/tmp/Mpeg2tsUnitTestRes/
+```
+Alternatively, the test can also be run using atest command.
+
+```
+atest Mpeg2tsUnitTest -- --enable-module-dynamic-download=true
+```
diff --git a/media/libstagefright/rtsp/NetworkUtils.cpp b/media/libstagefright/rtsp/NetworkUtils.cpp
index cc36b78..c053be8 100644
--- a/media/libstagefright/rtsp/NetworkUtils.cpp
+++ b/media/libstagefright/rtsp/NetworkUtils.cpp
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#include <unistd.h>
+
 //#define LOG_NDEBUG 0
 #define LOG_TAG "NetworkUtils"
 #include <utils/Log.h>
diff --git a/media/libstagefright/tests/writer/Android.bp b/media/libstagefright/tests/writer/Android.bp
index 7e169cb..d058ed3 100644
--- a/media/libstagefright/tests/writer/Android.bp
+++ b/media/libstagefright/tests/writer/Android.bp
@@ -28,6 +28,7 @@
         "libcutils",
         "liblog",
         "libutils",
+        "libmedia",
     ],
 
     static_libs: [
diff --git a/media/libstagefright/tests/writer/WriterListener.h b/media/libstagefright/tests/writer/WriterListener.h
new file mode 100644
index 0000000..81f0a7c
--- /dev/null
+++ b/media/libstagefright/tests/writer/WriterListener.h
@@ -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.
+ */
+
+#ifndef WRITER_LISTENER_H_
+#define WRITER_LISTENER_H_
+
+#include <mutex>
+
+#include <media/IMediaRecorderClient.h>
+#include <media/mediarecorder.h>
+
+using namespace android;
+using namespace std;
+
+class WriterListener : public BnMediaRecorderClient {
+  public:
+    WriterListener() : mSignaledSize(false), mSignaledDuration(false) {}
+
+    virtual void notify(int32_t msg, int32_t ext1, int32_t ext2) {
+        ALOGV("msg : %d, ext1 : %d, ext2 : %d", msg, ext1, ext2);
+        if (ext1 == MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED) {
+            mSignaledSize = true;
+        } else if (ext1 == MEDIA_RECORDER_INFO_MAX_DURATION_REACHED) {
+            mSignaledDuration = true;
+        }
+    }
+
+    volatile bool mSignaledSize;
+    volatile bool mSignaledDuration;
+};
+
+#endif  // WRITER_LISTENER_H_
diff --git a/media/libstagefright/tests/writer/WriterTest.cpp b/media/libstagefright/tests/writer/WriterTest.cpp
index ff063e3..3fa2aa6 100644
--- a/media/libstagefright/tests/writer/WriterTest.cpp
+++ b/media/libstagefright/tests/writer/WriterTest.cpp
@@ -87,36 +87,37 @@
          "bbb_mpeg4_352x288_512kbps_30fps.info", 352, 288, false},
 };
 
-class WriterTest : public ::testing::TestWithParam<pair<string, int32_t>> {
+class WriterTest {
   public:
     WriterTest() : mWriter(nullptr), mFileMeta(nullptr), mCurrentTrack(nullptr) {}
 
     ~WriterTest() {
-        if (mWriter) {
-            mWriter.clear();
-            mWriter = nullptr;
-        }
         if (mFileMeta) {
             mFileMeta.clear();
             mFileMeta = nullptr;
         }
         if (mCurrentTrack) {
+            mCurrentTrack->stop();
             mCurrentTrack.clear();
             mCurrentTrack = nullptr;
         }
+        if (mWriter) {
+            mWriter.clear();
+            mWriter = nullptr;
+        }
+        mBufferInfo.clear();
+        if (mInputStream.is_open()) mInputStream.close();
     }
 
-    virtual void SetUp() override {
+    void setupWriterType(string writerFormat) {
         mNumCsds = 0;
         mInputFrameId = 0;
         mWriterName = unknown_comp;
         mDisableTest = false;
-
         static const std::map<std::string, standardWriters> mapWriter = {
                 {"ogg", OGG},     {"aac", AAC},      {"aac_adts", AAC_ADTS}, {"webm", WEBM},
                 {"mpeg4", MPEG4}, {"amrnb", AMR_NB}, {"amrwb", AMR_WB},      {"mpeg2Ts", MPEG2TS}};
         // Find the component type
-        string writerFormat = GetParam().first;
         if (mapWriter.find(writerFormat) != mapWriter.end()) {
             mWriterName = mapWriter.at(writerFormat);
         }
@@ -126,11 +127,6 @@
         }
     }
 
-    virtual void TearDown() override {
-        mBufferInfo.clear();
-        if (mInputStream.is_open()) mInputStream.close();
-    }
-
     void getInputBufferInfo(string inputFileName, string inputInfo);
 
     int32_t createWriter(int32_t fd);
@@ -161,6 +157,12 @@
     vector<BufferInfo> mBufferInfo;
 };
 
+class WriteFunctionalityTest : public WriterTest,
+                               public ::testing::TestWithParam<pair<string, int32_t>> {
+  public:
+    virtual void SetUp() override { setupWriterType(GetParam().first); }
+};
+
 void WriterTest::getInputBufferInfo(string inputFileName, string inputInfo) {
     std::ifstream eleInfo;
     eleInfo.open(inputInfo.c_str());
@@ -270,7 +272,7 @@
     return;
 }
 
-TEST_P(WriterTest, CreateWriterTest) {
+TEST_P(WriteFunctionalityTest, CreateWriterTest) {
     if (mDisableTest) return;
     ALOGV("Tests the creation of writers");
 
@@ -284,7 +286,7 @@
             << "Failed to create writer for output format:" << GetParam().first;
 }
 
-TEST_P(WriterTest, WriterTest) {
+TEST_P(WriteFunctionalityTest, WriterTest) {
     if (mDisableTest) return;
     ALOGV("Checks if for a given input, a valid muxed file has been created or not");
 
@@ -321,7 +323,7 @@
     close(fd);
 }
 
-TEST_P(WriterTest, PauseWriterTest) {
+TEST_P(WriteFunctionalityTest, PauseWriterTest) {
     if (mDisableTest) return;
     ALOGV("Validates the pause() api of writers");
 
@@ -378,7 +380,7 @@
     close(fd);
 }
 
-TEST_P(WriterTest, MultiStartStopPauseTest) {
+TEST_P(WriteFunctionalityTest, MultiStartStopPauseTest) {
     // TODO: (b/144821804)
     // Enable the test for MPE2TS writer
     if (mDisableTest || mWriterName == standardWriters::MPEG2TS) return;
@@ -451,9 +453,112 @@
     close(fd);
 }
 
+class ListenerTest : public WriterTest,
+                     public ::testing::TestWithParam<
+                             tuple<string /* writerFormat*/, int32_t /* inputFileIdx*/,
+                                   float /* FileSizeLimit*/, float /* FileDurationLimit*/>> {
+  public:
+    virtual void SetUp() override {
+        tuple<string, int32_t, float, float> params = GetParam();
+        setupWriterType(get<0>(params));
+    }
+};
+
+TEST_P(ListenerTest, SetMaxFileLimitsTest) {
+    if (mDisableTest) return;
+    ALOGV("Validates writer when max file limits are set");
+
+    tuple<string, int32_t, float, float> params = GetParam();
+    string writerFormat = get<0>(params);
+    string outputFile = OUTPUT_FILE_NAME;
+    int32_t fd =
+            open(outputFile.c_str(), O_CREAT | O_LARGEFILE | O_TRUNC | O_RDWR, S_IRUSR | S_IWUSR);
+    ASSERT_GE(fd, 0) << "Failed to open output file to dump writer's data";
+
+    int32_t status = createWriter(fd);
+    ASSERT_EQ((status_t)OK, status) << "Failed to create writer for output format:" << writerFormat;
+
+    string inputFile = gEnv->getRes();
+    string inputInfo = gEnv->getRes();
+    configFormat param;
+    bool isAudio;
+    int32_t inputFileIdx = get<1>(params);
+    getFileDetails(inputFile, inputInfo, param, isAudio, inputFileIdx);
+    ASSERT_NE(inputFile.compare(gEnv->getRes()), 0) << "No input file specified";
+
+    ASSERT_NO_FATAL_FAILURE(getInputBufferInfo(inputFile, inputInfo));
+    status = addWriterSource(isAudio, param);
+    ASSERT_EQ((status_t)OK, status) << "Failed to add source for " << writerFormat << "Writer";
+
+    // Read file properties
+    struct stat buf;
+    status = stat(inputFile.c_str(), &buf);
+    ASSERT_EQ(0, status);
+
+    float fileSizeLimit = get<2>(params);
+    float fileDurationLimit = get<3>(params);
+    int64_t maxFileSize = 0;
+    int64_t maxFileDuration = 0;
+
+    size_t inputFileSize = buf.st_size;
+    int64_t lastFrameTimeStampUs = mBufferInfo[mBufferInfo.size() - 1].timeUs;
+    if (fileSizeLimit > 0) {
+        maxFileSize = (int64_t)(fileSizeLimit * inputFileSize);
+        mWriter->setMaxFileSize(maxFileSize);
+    }
+    if (fileDurationLimit > 0) {
+        maxFileDuration = (int64_t)(fileDurationLimit * lastFrameTimeStampUs);
+        mWriter->setMaxFileDuration(maxFileDuration);
+    }
+
+    sp<WriterListener> listener = new WriterListener();
+    ASSERT_NE(listener, nullptr) << "unable to allocate listener";
+
+    mWriter->setListener(listener);
+    status = mWriter->start(mFileMeta.get());
+
+    ASSERT_EQ((status_t)OK, status);
+    status = sendBuffersToWriter(mInputStream, mBufferInfo, mInputFrameId, mCurrentTrack, 0,
+                                 mBufferInfo.size(), false, listener);
+    ASSERT_EQ((status_t)OK, status) << writerFormat << " writer failed";
+    ASSERT_TRUE(mWriter->reachedEOS()) << "EOS not signalled.";
+
+    mCurrentTrack->stop();
+    status = mWriter->stop();
+    ASSERT_EQ((status_t)OK, status) << "Failed to stop the writer";
+    close(fd);
+
+    if (maxFileSize <= 0) {
+        ASSERT_FALSE(listener->mSignaledSize);
+    } else if (maxFileDuration <= 0) {
+        ASSERT_FALSE(listener->mSignaledDuration);
+    } else if (maxFileSize > 0 && maxFileDuration <= 0) {
+        ASSERT_TRUE(listener->mSignaledSize);
+    } else if (maxFileDuration > 0 && maxFileSize <= 0) {
+        ASSERT_TRUE(listener->mSignaledDuration);
+    } else {
+        ASSERT_TRUE(listener->mSignaledSize || listener->mSignaledDuration);
+    }
+
+    if (maxFileSize > 0) {
+        struct stat buf;
+        status = stat(outputFile.c_str(), &buf);
+        ASSERT_EQ(0, status);
+        ASSERT_LE(buf.st_size, maxFileSize);
+    }
+}
+
+// TODO: (b/150923387)
+// Add WEBM input
+INSTANTIATE_TEST_SUITE_P(
+        ListenerTestAll, ListenerTest,
+        ::testing::Values(make_tuple("ogg", 0, 0.7, 0.3), make_tuple("aac", 1, 0.6, 0.7),
+                          make_tuple("mpeg4", 1, 0.4, 0.3), make_tuple("amrnb", 3, 0.2, 0.6),
+                          make_tuple("amrwb", 4, 0.5, 0.5), make_tuple("mpeg2Ts", 1, 0.2, 1)));
+
 // TODO: (b/144476164)
 // Add AAC_ADTS, FLAC, AV1 input
-INSTANTIATE_TEST_SUITE_P(WriterTestAll, WriterTest,
+INSTANTIATE_TEST_SUITE_P(WriterTestAll, WriteFunctionalityTest,
                          ::testing::Values(make_pair("ogg", 0), make_pair("webm", 0),
                                            make_pair("aac", 1), make_pair("mpeg4", 1),
                                            make_pair("amrnb", 3), make_pair("amrwb", 4),
diff --git a/media/libstagefright/tests/writer/WriterUtility.cpp b/media/libstagefright/tests/writer/WriterUtility.cpp
index f24ccb6..a3043fe 100644
--- a/media/libstagefright/tests/writer/WriterUtility.cpp
+++ b/media/libstagefright/tests/writer/WriterUtility.cpp
@@ -24,9 +24,16 @@
 
 int32_t sendBuffersToWriter(ifstream &inputStream, vector<BufferInfo> &bufferInfo,
                             int32_t &inputFrameId, sp<MediaAdapter> &currentTrack, int32_t offset,
-                            int32_t range, bool isPaused) {
+                            int32_t range, bool isPaused, sp<WriterListener> listener) {
     while (1) {
         if (inputFrameId >= (int)bufferInfo.size() || inputFrameId >= (offset + range)) break;
+        if (listener != nullptr) {
+            if (listener->mSignaledDuration || listener->mSignaledSize) {
+                ALOGV("Max File limit reached. No more buffers will be sent to the writer");
+                break;
+            }
+        }
+
         int32_t size = bufferInfo[inputFrameId].size;
         char *data = (char *)malloc(size);
         if (!data) {
diff --git a/media/libstagefright/tests/writer/WriterUtility.h b/media/libstagefright/tests/writer/WriterUtility.h
index cdd6246..5e19973 100644
--- a/media/libstagefright/tests/writer/WriterUtility.h
+++ b/media/libstagefright/tests/writer/WriterUtility.h
@@ -27,8 +27,7 @@
 
 #include <media/stagefright/MediaAdapter.h>
 
-using namespace android;
-using namespace std;
+#include "WriterListener.h"
 
 #define CODEC_CONFIG_FLAG 32
 
@@ -43,7 +42,8 @@
 
 int32_t sendBuffersToWriter(ifstream &inputStream, vector<BufferInfo> &bufferInfo,
                             int32_t &inputFrameId, sp<MediaAdapter> &currentTrack, int32_t offset,
-                            int32_t range, bool isPaused = false);
+                            int32_t range, bool isPaused = false,
+                            sp<WriterListener> listener = nullptr);
 
 int32_t writeHeaderBuffers(ifstream &inputStream, vector<BufferInfo> &bufferInfo,
                            int32_t &inputFrameId, sp<AMessage> &format, int32_t numCsds);
diff --git a/media/libstagefright/timedtext/test/Android.bp b/media/libstagefright/timedtext/test/Android.bp
new file mode 100644
index 0000000..36f8891
--- /dev/null
+++ b/media/libstagefright/timedtext/test/Android.bp
@@ -0,0 +1,53 @@
+/*
+ * 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: "TimedTextUnitTest",
+    gtest: true,
+
+    srcs: [
+        "TimedTextUnitTest.cpp",
+    ],
+
+    static_libs: [
+        "libstagefright_timedtext",
+        "libstagefright_foundation",
+    ],
+
+    include_dirs: [
+        "frameworks/av/media/libstagefright",
+    ],
+
+    shared_libs: [
+        "liblog",
+        "libmedia",
+        "libbinder",
+    ],
+
+    cflags: [
+        "-Wno-multichar",
+        "-Werror",
+        "-Wall",
+    ],
+
+    sanitize: {
+        cfi: true,
+        misc_undefined: [
+            "unsigned-integer-overflow",
+            "signed-integer-overflow",
+        ],
+    },
+}
diff --git a/media/libstagefright/timedtext/test/AndroidTest.xml b/media/libstagefright/timedtext/test/AndroidTest.xml
new file mode 100644
index 0000000..3654e23
--- /dev/null
+++ b/media/libstagefright/timedtext/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 TimedText unit test">
+    <option name="test-suite-tag" value="TimedTextUnitTest" />
+    <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+        <option name="cleanup" value="true" />
+        <option name="push" value="TimedTextUnitTest->/data/local/tmp/TimedTextUnitTest" />
+        <option name="push-file"
+            key="https://storage.googleapis.com/android_media/frameworks/av/media/libstagefright/timedtext/test/TimedTextUnitTest.zip?unzip=true"
+            value="/data/local/tmp/TimedTextUnitTestRes/" />
+    </target_preparer>
+
+    <test class="com.android.tradefed.testtype.GTest" >
+        <option name="native-test-device-path" value="/data/local/tmp" />
+        <option name="module-name" value="TimedTextUnitTest" />
+        <option name="native-test-flag" value="-P /data/local/tmp/TimedTextUnitTestRes/" />
+    </test>
+</configuration>
diff --git a/media/libstagefright/timedtext/test/README.md b/media/libstagefright/timedtext/test/README.md
new file mode 100644
index 0000000..3a774bd
--- /dev/null
+++ b/media/libstagefright/timedtext/test/README.md
@@ -0,0 +1,40 @@
+## Media Testing ##
+---
+#### TimedText Unit Test :
+The TimedText Unit Test Suite validates the TextDescription class available in libstagefright.
+
+Run the following steps to build the test suite:
+```
+m TimedTextUnitTest
+```
+
+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/TimedTextUnitTest/TimedTextUnitTest /data/local/tmp/
+```
+
+To test 32-bit binary push binaries from nativetest.
+```
+adb push ${OUT}/data/nativetest/TimedTextUnitTest/TimedTextUnitTest /data/local/tmp/
+```
+
+The resource file for the tests is taken from [here](https://storage.googleapis.com/android_media/frameworks/av/media/libstagefright/timedtext/test/TimedTextUnitTest.zip).
+Download, unzip and push these files into device for testing.
+
+```
+adb push TimedTextUnitTestRes/. /data/local/tmp/
+```
+
+usage: TimedTextUnitTest -P \<path_to_folder\>
+```
+adb shell /data/local/tmp/TimedTextUnitTest -P /data/local/tmp/TimedTextUnitTestRes/
+```
+Alternatively, the test can also be run using atest command.
+
+```
+atest TimedTextUnitTest -- --enable-module-dynamic-download=true
+```
diff --git a/media/libstagefright/timedtext/test/TimedTextTestEnvironment.h b/media/libstagefright/timedtext/test/TimedTextTestEnvironment.h
new file mode 100644
index 0000000..52280c1
--- /dev/null
+++ b/media/libstagefright/timedtext/test/TimedTextTestEnvironment.h
@@ -0,0 +1,72 @@
+/*
+ * 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 __TIMEDTEXT_TEST_ENVIRONMENT_H__
+#define __TIMEDTEXT_TEST_ENVIRONMENT_H__
+
+#include <gtest/gtest.h>
+
+#include <getopt.h>
+
+using namespace std;
+
+class TimedTextTestEnvironment : public ::testing::Environment {
+  public:
+    TimedTextTestEnvironment() : 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 TimedTextTestEnvironment::initFromOptions(int argc, char **argv) {
+    static struct option options[] = {{"res", 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  // __TIMEDTEXT_TEST_ENVIRONMENT_H__
diff --git a/media/libstagefright/timedtext/test/TimedTextUnitTest.cpp b/media/libstagefright/timedtext/test/TimedTextUnitTest.cpp
new file mode 100644
index 0000000..d85ae39
--- /dev/null
+++ b/media/libstagefright/timedtext/test/TimedTextUnitTest.cpp
@@ -0,0 +1,379 @@
+/*
+ * 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 "TimedTextUnitTest"
+#include <utils/Log.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <fstream>
+
+#include <binder/Parcel.h>
+#include <media/stagefright/foundation/AString.h>
+#include <media/stagefright/foundation/ByteUtils.h>
+
+#include "timedtext/TextDescriptions.h"
+
+#include "TimedTextTestEnvironment.h"
+
+constexpr int32_t kStartTimeMs = 10000;
+
+enum {
+    // These keys must be in sync with the keys in
+    // frameworks/av/media/libstagefright/timedtext/TextDescriptions.h
+    KEY_DISPLAY_FLAGS = 1,
+    KEY_STYLE_FLAGS = 2,
+    KEY_BACKGROUND_COLOR_RGBA = 3,
+    KEY_HIGHLIGHT_COLOR_RGBA = 4,
+    KEY_SCROLL_DELAY = 5,
+    KEY_WRAP_TEXT = 6,
+    KEY_START_TIME = 7,
+    KEY_STRUCT_BLINKING_TEXT_LIST = 8,
+    KEY_STRUCT_FONT_LIST = 9,
+    KEY_STRUCT_HIGHLIGHT_LIST = 10,
+    KEY_STRUCT_HYPER_TEXT_LIST = 11,
+    KEY_STRUCT_KARAOKE_LIST = 12,
+    KEY_STRUCT_STYLE_LIST = 13,
+    KEY_STRUCT_TEXT_POS = 14,
+    KEY_STRUCT_JUSTIFICATION = 15,
+    KEY_STRUCT_TEXT = 16,
+
+    KEY_GLOBAL_SETTING = 101,
+    KEY_LOCAL_SETTING = 102,
+    KEY_START_CHAR = 103,
+    KEY_END_CHAR = 104,
+    KEY_FONT_ID = 105,
+    KEY_FONT_SIZE = 106,
+    KEY_TEXT_COLOR_RGBA = 107,
+};
+
+struct FontInfo {
+    int32_t displayFlag = -1;
+    int32_t horizontalJustification = -1;
+    int32_t verticalJustification = -1;
+    int32_t rgbaBackground = -1;
+    int32_t leftPos = -1;
+    int32_t topPos = -1;
+    int32_t bottomPos = -1;
+    int32_t rightPos = -1;
+    int32_t startchar = -1;
+    int32_t endChar = -1;
+    int32_t fontId = -1;
+    int32_t faceStyle = -1;
+    int32_t fontSize = -1;
+    int32_t rgbaText = -1;
+    int32_t entryCount = -1;
+};
+
+struct FontRecord {
+    int32_t fontID = -1;
+    int32_t fontNameLength = -1;
+    const uint8_t *font = nullptr;
+};
+
+using namespace android;
+
+static TimedTextTestEnvironment *gEnv = nullptr;
+
+class TimedTextUnitTest : public ::testing::TestWithParam</*filename*/ string> {
+  public:
+    TimedTextUnitTest(){};
+
+    ~TimedTextUnitTest() {
+        if (mEleStream) mEleStream.close();
+    }
+
+    virtual void SetUp() override {
+        mInputFileName = gEnv->getRes() + GetParam();
+        mEleStream.open(mInputFileName, ifstream::binary);
+        ASSERT_EQ(mEleStream.is_open(), true) << "Failed to open " << GetParam();
+
+        struct stat buf;
+        status_t status = stat(mInputFileName.c_str(), &buf);
+        ASSERT_EQ(status, 0) << "Failed to get properties of input file: " << GetParam();
+        mFileSize = buf.st_size;
+        ALOGI("Size of the input file %s = %zu", GetParam().c_str(), mFileSize);
+    }
+
+    string mInputFileName;
+    size_t mFileSize;
+    ifstream mEleStream;
+};
+
+class SRTDescriptionTest : public TimedTextUnitTest {
+  public:
+    virtual void SetUp() override { TimedTextUnitTest::SetUp(); }
+};
+
+class Text3GPPDescriptionTest : public TimedTextUnitTest {
+  public:
+    virtual void SetUp() override { TimedTextUnitTest::SetUp(); }
+};
+
+TEST_P(SRTDescriptionTest, extractSRTDescriptionTest) {
+    char data[mFileSize];
+    mEleStream.read(data, sizeof(data));
+    ASSERT_EQ(mEleStream.gcount(), mFileSize);
+
+    Parcel parcel;
+    int32_t flag = TextDescriptions::OUT_OF_BAND_TEXT_SRT | TextDescriptions::LOCAL_DESCRIPTIONS;
+    status_t status = TextDescriptions::getParcelOfDescriptions((const uint8_t *)data, mFileSize,
+                                                                flag, kStartTimeMs, &parcel);
+    ASSERT_EQ(status, 0) << "getParcelOfDescriptions returned error";
+    ALOGI("Size of the Parcel: %zu", parcel.dataSize());
+    ASSERT_GT(parcel.dataSize(), 0) << "Parcel is empty";
+
+    parcel.setDataPosition(0);
+    int32_t key = parcel.readInt32();
+    ASSERT_EQ(key, KEY_LOCAL_SETTING) << "Parcel has invalid key";
+
+    key = parcel.readInt32();
+    ASSERT_EQ(key, KEY_START_TIME) << "Parcel has invalid start time key";
+    ASSERT_EQ(parcel.readInt32(), kStartTimeMs) << "Parcel has invalid timings";
+
+    key = parcel.readInt32();
+    ASSERT_EQ(key, KEY_STRUCT_TEXT) << "Parcel has invalid struct text key";
+    ASSERT_EQ(parcel.readInt32(), mFileSize) << "Parcel has invalid text data";
+    int32_t fileSize = parcel.readInt32();
+    ASSERT_EQ(fileSize, mFileSize) << "Parcel has invalid file size value";
+    uint8_t tmpData[fileSize];
+    status = parcel.read((void *)tmpData, fileSize);
+    ASSERT_EQ(status, 0) << "Failed to read the data from parcel";
+    // To make sure end of parcel is reached
+    ASSERT_EQ(parcel.dataAvail(), 0) << "Parcel has some data left to read";
+}
+
+// This test uses the properties of tx3g box mentioned in 3GPP Timed Text Format
+// Specification#: 26.245 / Section: 5.16(Sample Description Format)
+// https://www.3gpp.org/ftp/Specs/archive/26_series/26.245/
+
+TEST_P(Text3GPPDescriptionTest, Text3GPPGlobalDescriptionTest) {
+    char data[mFileSize];
+    mEleStream.read(data, sizeof(data));
+    ASSERT_EQ(mEleStream.gcount(), mFileSize);
+
+    const uint8_t *tmpData = (const uint8_t *)data;
+    int32_t remaining = mFileSize;
+    FontInfo fontInfo;
+    vector<FontRecord> fontRecordEntries;
+
+    // Skipping the bytes containing information about the type of subbox(tx3g)
+    tmpData += 16;
+    remaining -= 16;
+
+    fontInfo.displayFlag = U32_AT(tmpData);
+    ALOGI("Display flag: %d", fontInfo.displayFlag);
+    fontInfo.horizontalJustification = tmpData[4];
+    ALOGI("Horizontal Justification: %d", fontInfo.horizontalJustification);
+    fontInfo.verticalJustification = tmpData[5];
+    ALOGI("Vertical Justification: %d", fontInfo.verticalJustification);
+    fontInfo.rgbaBackground =
+            *(tmpData + 6) << 24 | *(tmpData + 7) << 16 | *(tmpData + 8) << 8 | *(tmpData + 9);
+    ALOGI("rgba value of background: %d", fontInfo.rgbaBackground);
+
+    tmpData += 10;
+    remaining -= 10;
+
+    if (remaining >= 8) {
+        fontInfo.leftPos = U16_AT(tmpData);
+        ALOGI("Left: %d", fontInfo.leftPos);
+        fontInfo.topPos = U16_AT(tmpData + 2);
+        ALOGI("Top: %d", fontInfo.topPos);
+        fontInfo.bottomPos = U16_AT(tmpData + 4);
+        ALOGI("Bottom: %d", fontInfo.bottomPos);
+        fontInfo.rightPos = U16_AT(tmpData + 6);
+        ALOGI("Right: %d", fontInfo.rightPos);
+
+        tmpData += 8;
+        remaining -= 8;
+
+        if (remaining >= 12) {
+            fontInfo.startchar = U16_AT(tmpData);
+            ALOGI("Start character: %d", fontInfo.startchar);
+            fontInfo.endChar = U16_AT(tmpData + 2);
+            ALOGI("End character: %d", fontInfo.endChar);
+            fontInfo.fontId = U16_AT(tmpData + 4);
+            ALOGI("Value of font Identifier: %d", fontInfo.fontId);
+            fontInfo.faceStyle = *(tmpData + 6);
+            ALOGI("Face style flag : %d", fontInfo.faceStyle);
+            fontInfo.fontSize = *(tmpData + 7);
+            ALOGI("Size of the font: %d", fontInfo.fontSize);
+            fontInfo.rgbaText = *(tmpData + 8) << 24 | *(tmpData + 9) << 16 | *(tmpData + 10) << 8 |
+                                *(tmpData + 11);
+            ALOGI("rgba value of the text: %d", fontInfo.rgbaText);
+
+            tmpData += 12;
+            remaining -= 12;
+
+            if (remaining >= 10) {
+                // Skipping the bytes containing information about the type of subbox(ftab)
+                fontInfo.entryCount = U16_AT(tmpData + 8);
+                ALOGI("Value of entry count: %d", fontInfo.entryCount);
+
+                tmpData += 10;
+                remaining -= 10;
+
+                for (int32_t i = 0; i < fontInfo.entryCount; i++) {
+                    if (remaining < 3) break;
+                    int32_t tempFontID = U16_AT(tmpData);
+                    ALOGI("Font Id: %d", tempFontID);
+                    int32_t tempFontNameLength = *(tmpData + 2);
+                    ALOGI("Length of font name: %d", tempFontNameLength);
+
+                    tmpData += 3;
+                    remaining -= 3;
+
+                    if (remaining < tempFontNameLength) break;
+                    const uint8_t *tmpFont = tmpData;
+                    char *tmpFontName = strndup((const char *)tmpFont, tempFontNameLength);
+                    ASSERT_NE(tmpFontName, nullptr) << "Font Name is null";
+                    ALOGI("FontName = %s", tmpFontName);
+                    free(tmpFontName);
+                    tmpData += tempFontNameLength;
+                    remaining -= tempFontNameLength;
+                    fontRecordEntries.push_back({tempFontID, tempFontNameLength, tmpFont});
+                }
+            }
+        }
+    }
+
+    Parcel parcel;
+    int32_t flag = TextDescriptions::IN_BAND_TEXT_3GPP | TextDescriptions::GLOBAL_DESCRIPTIONS;
+    status_t status = TextDescriptions::getParcelOfDescriptions((const uint8_t *)data, mFileSize,
+                                                                flag, kStartTimeMs, &parcel);
+    ASSERT_EQ(status, 0) << "getParcelOfDescriptions returned error";
+    ALOGI("Size of the Parcel: %zu", parcel.dataSize());
+    ASSERT_GT(parcel.dataSize(), 0) << "Parcel is empty";
+
+    parcel.setDataPosition(0);
+    int32_t key = parcel.readInt32();
+    ASSERT_EQ(key, KEY_GLOBAL_SETTING) << "Parcel has invalid key";
+
+    key = parcel.readInt32();
+    ASSERT_EQ(key, KEY_DISPLAY_FLAGS) << "Parcel has invalid DISPLAY FLAGS Key";
+    ASSERT_EQ(parcel.readInt32(), fontInfo.displayFlag)
+            << "Parcel has invalid value of display flag";
+
+    key = parcel.readInt32();
+    ASSERT_EQ(key, KEY_STRUCT_JUSTIFICATION) << "Parcel has invalid STRUCT JUSTIFICATION key";
+    ASSERT_EQ(parcel.readInt32(), fontInfo.horizontalJustification)
+            << "Parcel has invalid value of Horizontal justification";
+    ASSERT_EQ(parcel.readInt32(), fontInfo.verticalJustification)
+            << "Parcel has invalid value of Vertical justification";
+
+    key = parcel.readInt32();
+    ASSERT_EQ(key, KEY_BACKGROUND_COLOR_RGBA) << "Parcel has invalid BACKGROUND COLOR key";
+    ASSERT_EQ(parcel.readInt32(), fontInfo.rgbaBackground)
+            << "Parcel has invalid rgba background color value";
+
+    if (parcel.dataAvail() == 0) {
+        ALOGV("Completed reading the parcel");
+        return;
+    }
+
+    key = parcel.readInt32();
+    ASSERT_EQ(key, KEY_STRUCT_TEXT_POS) << "Parcel has invalid STRUCT TEXT POSITION key";
+    ASSERT_EQ(parcel.readInt32(), fontInfo.leftPos)
+            << "Parcel has invalid rgba background color value";
+    ASSERT_EQ(parcel.readInt32(), fontInfo.topPos)
+            << "Parcel has invalid rgba background color value";
+    ASSERT_EQ(parcel.readInt32(), fontInfo.bottomPos)
+            << "Parcel has invalid rgba background color value";
+    ASSERT_EQ(parcel.readInt32(), fontInfo.rightPos)
+            << "Parcel has invalid rgba background color value";
+
+    if (parcel.dataAvail() == 0) {
+        ALOGV("Completed reading the parcel");
+        return;
+    }
+
+    key = parcel.readInt32();
+    ASSERT_EQ(key, KEY_STRUCT_STYLE_LIST) << "Parcel has invalid STRUCT STYLE LIST key";
+
+    key = parcel.readInt32();
+    ASSERT_EQ(key, KEY_START_CHAR) << "Parcel has invalid START CHAR key";
+    ASSERT_EQ(parcel.readInt32(), fontInfo.startchar)
+            << "Parcel has invalid value of start character";
+
+    key = parcel.readInt32();
+    ASSERT_EQ(key, KEY_END_CHAR) << "Parcel has invalid END CHAR key";
+    ASSERT_EQ(parcel.readInt32(), fontInfo.endChar) << "Parcel has invalid value of end character";
+
+    key = parcel.readInt32();
+    ASSERT_EQ(key, KEY_FONT_ID) << "Parcel has invalid FONT ID key";
+    ASSERT_EQ(parcel.readInt32(), fontInfo.fontId) << "Parcel has invalid value of font Id";
+
+    key = parcel.readInt32();
+    ASSERT_EQ(key, KEY_STYLE_FLAGS) << "Parcel has invalid STYLE FLAGS key";
+    ASSERT_EQ(parcel.readInt32(), fontInfo.faceStyle) << "Parcel has invalid value of style flags";
+
+    key = parcel.readInt32();
+    ASSERT_EQ(key, KEY_FONT_SIZE) << "Parcel has invalid FONT SIZE key";
+    ASSERT_EQ(parcel.readInt32(), fontInfo.fontSize) << "Parcel has invalid value of font size";
+
+    key = parcel.readInt32();
+    ASSERT_EQ(key, KEY_TEXT_COLOR_RGBA) << "Parcel has invalid TEXT COLOR RGBA key";
+    ASSERT_EQ(parcel.readInt32(), fontInfo.rgbaText) << "Parcel has invalid rgba text color value";
+
+    if (parcel.dataAvail() == 0) {
+        ALOGV("Completed reading the parcel");
+        return;
+    }
+
+    key = parcel.readInt32();
+    ASSERT_EQ(key, KEY_STRUCT_FONT_LIST) << "Parcel has invalid STRUCT FONT LIST key";
+    ASSERT_EQ(parcel.readInt32(), fontInfo.entryCount) << "Parcel has invalid value of entry count";
+    ASSERT_EQ(fontInfo.entryCount, fontRecordEntries.size())
+            << "Array size does not match expected number of entries";
+    for (int32_t i = 0; i < fontInfo.entryCount; i++) {
+        ASSERT_EQ(parcel.readInt32(), fontRecordEntries[i].fontID)
+                << "Parcel has invalid value of font Id";
+        ASSERT_EQ(parcel.readInt32(), fontRecordEntries[i].fontNameLength)
+                << "Parcel has invalid value of font name length";
+        uint8_t fontName[fontRecordEntries[i].fontNameLength];
+        // written with writeByteArray() writes count, then the actual data
+        ASSERT_EQ(parcel.readInt32(), fontRecordEntries[i].fontNameLength);
+        status = parcel.read((void *)fontName, fontRecordEntries[i].fontNameLength);
+        ASSERT_EQ(status, 0) << "Failed to read the font name from parcel";
+        ASSERT_EQ(memcmp(fontName, fontRecordEntries[i].font, fontRecordEntries[i].fontNameLength),
+                  0)
+                << "Parcel has invalid font";
+    }
+    // To make sure end of parcel is reached
+    ASSERT_EQ(parcel.dataAvail(), 0) << "Parcel has some data left to read";
+}
+
+INSTANTIATE_TEST_SUITE_P(TimedTextUnitTestAll, SRTDescriptionTest,
+                         ::testing::Values(("sampleTest1.srt"),
+                                           ("sampleTest2.srt")));
+
+INSTANTIATE_TEST_SUITE_P(TimedTextUnitTestAll, Text3GPPDescriptionTest,
+                         ::testing::Values(("tx3gBox1"),
+                                           ("tx3gBox2")));
+
+int main(int argc, char **argv) {
+    gEnv = new TimedTextTestEnvironment();
+    ::testing::AddGlobalTestEnvironment(gEnv);
+    ::testing::InitGoogleTest(&argc, argv);
+    int status = gEnv->initFromOptions(argc, argv);
+    if (status == 0) {
+        status = RUN_ALL_TESTS();
+        ALOGV("Test result = %d\n", status);
+    }
+    return status;
+}
diff --git a/media/libstagefright/xmlparser/MediaCodecsXmlParser.cpp b/media/libstagefright/xmlparser/MediaCodecsXmlParser.cpp
index a232150..3be5e74 100644
--- a/media/libstagefright/xmlparser/MediaCodecsXmlParser.cpp
+++ b/media/libstagefright/xmlparser/MediaCodecsXmlParser.cpp
@@ -1525,7 +1525,7 @@
                 nodeInfo.attributeList.push_back(Attribute{"rank", rank});
             }
             nodeList->insert(std::make_pair(
-                    std::move(order), std::move(nodeInfo)));
+                    order, std::move(nodeInfo)));
         }
     }
 }
diff --git a/media/libstagefright/xmlparser/test/Android.bp b/media/libstagefright/xmlparser/test/Android.bp
new file mode 100644
index 0000000..6d97c96
--- /dev/null
+++ b/media/libstagefright/xmlparser/test/Android.bp
@@ -0,0 +1,52 @@
+/*
+ * 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: "XMLParserTest",
+    gtest: true,
+
+    srcs: [
+        "XMLParserTest.cpp",
+    ],
+
+    shared_libs: [
+        "liblog",
+        "libstagefright_xmlparser",
+    ],
+
+    cflags: [
+        "-Werror",
+        "-Wall",
+    ],
+
+    data: [":xmlparsertest_test_files",],
+
+    sanitize: {
+        misc_undefined: [
+            "unsigned-integer-overflow",
+            "signed-integer-overflow",
+        ],
+        cfi: true,
+    },
+}
+
+filegroup {
+    name: "xmlparsertest_test_files",
+    srcs: [
+        "testdata/media_codecs_unit_test.xml",
+        "testdata/media_codecs_unit_test_caller.xml",
+    ],
+}
diff --git a/media/libstagefright/xmlparser/test/AndroidTest.xml b/media/libstagefright/xmlparser/test/AndroidTest.xml
new file mode 100644
index 0000000..2e11b1b
--- /dev/null
+++ b/media/libstagefright/xmlparser/test/AndroidTest.xml
@@ -0,0 +1,28 @@
+<?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 xml parser unit test">
+    <option name="test-suite-tag" value="XMLParserTest" />
+    <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+        <option name="cleanup" value="true" />
+        <option name="push" value="media_codecs_unit_test.xml->/data/local/tmp/media_codecs_unit_test.xml" />
+        <option name="push" value="media_codecs_unit_test_caller.xml->/data/local/tmp/media_codecs_unit_test_caller.xml" />
+        <option name="push" value="XMLParserTest->/data/local/tmp/XMLParserTest" />
+    </target_preparer>
+   <test class="com.android.tradefed.testtype.GTest" >
+        <option name="native-test-device-path" value="/data/local/tmp" />
+        <option name="module-name" value="XMLParserTest" />
+    </test>
+</configuration>
diff --git a/media/libstagefright/xmlparser/test/README.md b/media/libstagefright/xmlparser/test/README.md
new file mode 100644
index 0000000..e9363fd
--- /dev/null
+++ b/media/libstagefright/xmlparser/test/README.md
@@ -0,0 +1,33 @@
+## Media Testing ##
+---
+#### XML Parser
+The XMLParser Test Suite validates the XMLParser available in libstagefright.
+
+Run the following steps to build the test suite:
+```
+m XMLParserTest
+```
+
+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/XMLParserTest/XMLParserTest /data/local/tmp/
+```
+
+To test 32-bit binary push binaries from nativetest.
+```
+adb push ${OUT}/data/nativetest/XMLParserTest/XMLParserTest /data/local/tmp/
+```
+
+usage: XMLParserTest
+```
+adb shell /data/local/tmp/XMLParserTest
+```
+Alternatively, the test can also be run using atest command.
+
+```
+atest XMLParserTest
+```
diff --git a/media/libstagefright/xmlparser/test/XMLParserTest.cpp b/media/libstagefright/xmlparser/test/XMLParserTest.cpp
new file mode 100644
index 0000000..9ddd374
--- /dev/null
+++ b/media/libstagefright/xmlparser/test/XMLParserTest.cpp
@@ -0,0 +1,392 @@
+/*
+ * 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 "XMLParserTest"
+
+#include <utils/Log.h>
+
+#include <fstream>
+
+#include <media/stagefright/xmlparser/MediaCodecsXmlParser.h>
+
+#include "XMLParserTestEnvironment.h"
+
+#define XML_FILE_NAME "media_codecs_unit_test_caller.xml"
+
+using namespace android;
+
+static XMLParserTestEnvironment *gEnv = nullptr;
+
+struct CodecProperties {
+    string codecName;
+    MediaCodecsXmlParser::CodecProperties codecProp;
+};
+
+struct RoleProperties {
+    string roleName;
+    string typeName;
+    string codecName;
+    bool isEncoder;
+    size_t order;
+    vector<pair<string, string>> attributeMap;
+};
+
+class XMLParseTest : public ::testing::Test {
+  public:
+    ~XMLParseTest() {
+        if (mEleStream.is_open()) mEleStream.close();
+        mInputDataVector.clear();
+        mInputRoleVector.clear();
+    }
+
+    virtual void SetUp() override { setUpDatabase(); }
+
+    void setUpDatabase();
+
+    void setCodecProperties(string codecName, bool isEncoder, int32_t order, set<string> quirkSet,
+                            set<string> domainSet, set<string> variantSet, string typeName,
+                            vector<pair<string, string>> domain, vector<string> aliases,
+                            string rank);
+
+    void setRoleProperties(string roleName, bool isEncoder, int32_t order, string typeName,
+                           string codecName, vector<pair<string, string>> domain);
+
+    void setServiceAttribute(map<string, string> serviceAttributeNameValuePair);
+
+    void printCodecMap(const MediaCodecsXmlParser::Codec mcodec);
+
+    void checkRoleMap(int32_t index, bool isEncoder, string typeName, string codecName,
+                      vector<pair<string, string>> attrMap);
+
+    bool compareMap(const map<string, string> &lhs, const map<string, string> &rhs);
+
+    ifstream mEleStream;
+    MediaCodecsXmlParser mParser;
+    vector<CodecProperties> mInputDataVector;
+    vector<RoleProperties> mInputRoleVector;
+    map<string, string> mInputServiceAttributeMap;
+};
+
+void XMLParseTest::setUpDatabase() {
+    // The values set below are specific to test vector testdata/media_codecs_unit_test.xml
+    setCodecProperties("test1.decoder", false, 1, {"attribute::disabled", "quirk::quirk1"},
+                       {"telephony"}, {}, "audio/mpeg", {}, {"alias1.decoder"}, "4");
+
+    setCodecProperties("test2.decoder", false, 2, {"quirk::quirk1"}, {}, {}, "audio/3gpp", {}, {},
+                       "");
+
+    setCodecProperties("test3.decoder", false, 3, {}, {}, {}, "audio/amr-wb",
+                       {
+                               pair<string, string>("feature-feature1", "feature1Val"),
+                               pair<string, string>("feature-feature2", "0"),
+                               pair<string, string>("feature-feature3", "0"),
+                       },
+                       {}, "");
+
+    setCodecProperties("test4.decoder", false, 4, {}, {}, {}, "audio/flac",
+                       {pair<string, string>("feature-feature1", "feature1Val")}, {}, "");
+
+    setCodecProperties("test5.decoder", false, 5, {"attribute::attributeQuirk1"}, {}, {},
+                       "audio/g711-mlaw", {}, {}, "");
+
+    setCodecProperties("test6.decoder", false, 6, {}, {}, {"variant1", "variant2"},
+                       "audio/mp4a-latm",
+                       {pair<string, string>("variant1:::variant1Limit1-range",
+                                             "variant1Limit1Min-variant1Limit1Max"),
+                        pair<string, string>("variant1:::variant1Limit2-range",
+                                             "variant1Limit2Low-variant1Limit2High"),
+                        pair<string, string>("variant2:::variant2Limit1", "variant2Limit1Value")},
+                       {}, "");
+
+    setCodecProperties(
+            "test7.decoder", false, 7, {}, {}, {}, "audio/vorbis",
+            {
+                    pair<string, string>("-min-limit1", "limit1Min"),
+                    /*pair<string, string>("limit1-in", "limit1In"),*/
+                    pair<string, string>("limit2-range", "limit2Min-limit2Max"),
+                    pair<string, string>("limit2-scale", "limit2Scale"),
+                    pair<string, string>("limit3-default", "limit3Val3"),
+                    pair<string, string>("limit3-ranges", "limit3Val1,limit3Val2,limit3Val3"),
+            },
+            {}, "");
+
+    setCodecProperties("test8.encoder", true, 8, {}, {}, {}, "audio/opus",
+                       {pair<string, string>("max-limit1", "limit1Max")}, {}, "");
+
+    setRoleProperties("audio_decoder.mp3", false, 1, "audio/mpeg", "test1.decoder",
+                      {pair<string, string>("attribute::disabled", "present"),
+                       pair<string, string>("rank", "4")});
+
+    setRoleProperties("audio_decoder.amrnb", false, 2, "audio/3gpp", "test2.decoder", {});
+
+    setRoleProperties("audio_decoder.amrwb", false, 3, "audio/amr-wb", "test3.decoder",
+                      {pair<string, string>("feature-feature1", "feature1Val"),
+                       pair<string, string>("feature-feature2", "0"),
+                       pair<string, string>("feature-feature3", "0")});
+
+    setRoleProperties("audio/flac", false, 4, "audio/flac", "test4.decoder",
+                      {pair<string, string>("feature-feature1", "feature1Val")});
+
+    setRoleProperties("audio_decoder.g711mlaw", false, 5, "audio/g711-mlaw", "test5.decoder",
+                      {pair<string, string>("attribute::attributeQuirk1", "present")});
+
+    setRoleProperties("audio_decoder.aac", false, 6, "audio/mp4a-latm", "test6.decoder",
+                      {pair<string, string>("variant1:::variant1Limit1-range",
+                                            "variant1Limit1Min-variant1Limit1Max"),
+                       pair<string, string>("variant1:::variant1Limit2-range",
+                                            "variant1Limit2Low-variant1Limit2High"),
+                       pair<string, string>("variant2:::variant2Limit1", "variant2Limit1Value")});
+
+    setRoleProperties("audio_decoder.vorbis", false, 7, "audio/vorbis", "test7.decoder",
+                      {pair<string, string>("-min-limit1", "limit1Min"),
+                       /*pair<string, string>("limit1-in", "limit1In"),*/
+                       pair<string, string>("limit2-range", "limit2Min-limit2Max"),
+                       pair<string, string>("limit2-scale", "limit2Scale"),
+                       pair<string, string>("limit3-default", "limit3Val3"),
+                       pair<string, string>("limit3-ranges", "limit3Val1,limit3Val2,limit3Val3")});
+
+    setRoleProperties("audio_encoder.opus", true, 8, "audio/opus", "test8.encoder",
+                      {pair<string, string>("max-limit1", "limit1Max")});
+
+    setServiceAttribute(
+            {pair<string, string>("domain-telephony", "0"), pair<string, string>("domain-tv", "0"),
+             pair<string, string>("setting2", "0"), pair<string, string>("variant-variant1", "0")});
+}
+
+bool XMLParseTest::compareMap(const map<string, string> &lhs, const map<string, string> &rhs) {
+    return lhs.size() == rhs.size() && equal(lhs.begin(), lhs.end(), rhs.begin());
+}
+
+void XMLParseTest::setCodecProperties(string codecName, bool isEncoder, int32_t order,
+                                      set<string> quirkSet, set<string> domainSet,
+                                      set<string> variantSet, string typeName,
+                                      vector<pair<string, string>> domain, vector<string> aliases,
+                                      string rank) {
+    map<string, string> AttributeMapDB;
+    for (const auto &AttrStr : domain) {
+        AttributeMapDB.insert(AttrStr);
+    }
+    map<string, MediaCodecsXmlParser::AttributeMap> TypeMapDataBase;
+    TypeMapDataBase.insert(
+            pair<string, MediaCodecsXmlParser::AttributeMap>(typeName, AttributeMapDB));
+    CodecProperties codecProperty;
+    codecProperty.codecName = codecName;
+    codecProperty.codecProp.isEncoder = isEncoder;
+    codecProperty.codecProp.order = order;
+    codecProperty.codecProp.quirkSet = quirkSet;
+    codecProperty.codecProp.domainSet = domainSet;
+    codecProperty.codecProp.variantSet = variantSet;
+    codecProperty.codecProp.typeMap = TypeMapDataBase;
+    codecProperty.codecProp.aliases = aliases;
+    codecProperty.codecProp.rank = rank;
+    mInputDataVector.push_back(codecProperty);
+}
+
+void XMLParseTest::setRoleProperties(string roleName, bool isEncoder, int32_t order,
+                                     string typeName, string codecName,
+                                     vector<pair<string, string>> attributeNameValuePair) {
+    struct RoleProperties roleProperty;
+    roleProperty.roleName = roleName;
+    roleProperty.typeName = typeName;
+    roleProperty.codecName = codecName;
+    roleProperty.isEncoder = isEncoder;
+    roleProperty.order = order;
+    roleProperty.attributeMap = attributeNameValuePair;
+    mInputRoleVector.push_back(roleProperty);
+}
+
+void XMLParseTest::setServiceAttribute(map<string, string> serviceAttributeNameValuePair) {
+    for (const auto &serviceAttrStr : serviceAttributeNameValuePair) {
+        mInputServiceAttributeMap.insert(serviceAttrStr);
+    }
+}
+
+void XMLParseTest::printCodecMap(const MediaCodecsXmlParser::Codec mcodec) {
+    const string &name = mcodec.first;
+    ALOGV("codec name = %s\n", name.c_str());
+    const MediaCodecsXmlParser::CodecProperties &properties = mcodec.second;
+    bool isEncoder = properties.isEncoder;
+    ALOGV("isEncoder = %d\n", isEncoder);
+    size_t order = properties.order;
+    ALOGV("order = %zu\n", order);
+    string rank = properties.rank;
+    ALOGV("rank = %s\n", rank.c_str());
+
+    for (auto &itrQuirkSet : properties.quirkSet) {
+        ALOGV("quirkSet= %s", itrQuirkSet.c_str());
+    }
+
+    for (auto &itrDomainSet : properties.domainSet) {
+        ALOGV("domainSet= %s", itrDomainSet.c_str());
+    }
+
+    for (auto &itrVariantSet : properties.variantSet) {
+        ALOGV("variantSet= %s", itrVariantSet.c_str());
+    }
+
+    map<string, MediaCodecsXmlParser::AttributeMap> TypeMap = properties.typeMap;
+    ALOGV("The TypeMap is :");
+
+    for (auto &itrTypeMap : TypeMap) {
+        ALOGV("itrTypeMap->first\t%s\t", itrTypeMap.first.c_str());
+
+        for (auto &itrAttributeMap : itrTypeMap.second) {
+            ALOGV("AttributeMap->first = %s", itrAttributeMap.first.c_str());
+            ALOGV("AttributeMap->second = %s", itrAttributeMap.second.c_str());
+        }
+    }
+}
+
+void XMLParseTest::checkRoleMap(int32_t index, bool isEncoder, string typeName, string codecName,
+                                vector<pair<string, string>> AttributePairMap) {
+    ASSERT_EQ(isEncoder, mInputRoleVector.at(index).isEncoder)
+            << "Invalid RoleMap data. IsEncoder mismatch";
+    ASSERT_EQ(typeName, mInputRoleVector.at(index).typeName)
+            << "Invalid RoleMap data. typeName mismatch";
+    ASSERT_EQ(codecName, mInputRoleVector.at(index).codecName)
+            << "Invalid RoleMap data. codecName mismatch";
+
+    vector<pair<string, string>>::iterator itr_attributeMapDB =
+            (mInputRoleVector.at(index).attributeMap).begin();
+    vector<pair<string, string>>::iterator itr_attributeMap = AttributePairMap.begin();
+    for (; itr_attributeMap != AttributePairMap.end() &&
+           itr_attributeMapDB != mInputRoleVector.at(index).attributeMap.end();
+         ++itr_attributeMap, ++itr_attributeMapDB) {
+        string attributeName = itr_attributeMap->first;
+        string attributeNameDB = itr_attributeMapDB->first;
+        string attributevalue = itr_attributeMap->second;
+        string attributeValueDB = itr_attributeMapDB->second;
+        ASSERT_EQ(attributeName, attributeNameDB)
+                << "Invalid RoleMap data. Attribute name mismatch\t" << attributeName << " != "
+                << "attributeNameDB";
+        ASSERT_EQ(attributevalue, attributeValueDB)
+                << "Invalid RoleMap data. Attribute value mismatch\t" << attributevalue << " != "
+                << "attributeValueDB";
+    }
+}
+
+TEST_F(XMLParseTest, CodecMapParseTest) {
+    string inputFileName = gEnv->getRes() + XML_FILE_NAME;
+    mEleStream.open(inputFileName, ifstream::binary);
+    ASSERT_EQ(mEleStream.is_open(), true) << "Failed to open inputfile " << inputFileName;
+
+    mParser.parseXmlPath(inputFileName);
+    for (const MediaCodecsXmlParser::Codec &mcodec : mParser.getCodecMap()) {
+        printCodecMap(mcodec);
+        const MediaCodecsXmlParser::CodecProperties &properties = mcodec.second;
+        int32_t index = properties.order - 1;
+        ASSERT_GE(index, 0) << "Invalid order";
+        ASSERT_EQ(mInputDataVector.at(index).codecName, mcodec.first.c_str())
+                << "Invalid CodecMap data. codecName mismatch";
+        ASSERT_EQ(properties.isEncoder, mInputDataVector.at(index).codecProp.isEncoder)
+                << "Invalid CodecMap data. isEncoder mismatch";
+        ASSERT_EQ(properties.order, mInputDataVector.at(index).codecProp.order)
+                << "Invalid CodecMap data. order mismatch";
+
+        set<string> quirkSetDB = mInputDataVector.at(index).codecProp.quirkSet;
+        set<string> quirkSet = properties.quirkSet;
+        set<string> quirkDifference;
+        set_difference(quirkSetDB.begin(), quirkSetDB.end(), quirkSet.begin(), quirkSet.end(),
+                       inserter(quirkDifference, quirkDifference.end()));
+        ASSERT_EQ(quirkDifference.size(), 0) << "CodecMap:quirk mismatch";
+
+        map<string, MediaCodecsXmlParser::AttributeMap> TypeMapDB =
+                mInputDataVector.at(index).codecProp.typeMap;
+        map<string, MediaCodecsXmlParser::AttributeMap> TypeMap = properties.typeMap;
+        map<string, MediaCodecsXmlParser::AttributeMap>::iterator itr_TypeMapDB = TypeMapDB.begin();
+        map<string, MediaCodecsXmlParser::AttributeMap>::iterator itr_TypeMap = TypeMap.begin();
+
+        ASSERT_EQ(TypeMapDB.size(), TypeMap.size())
+                << "Invalid CodecMap data. Typemap size mismatch";
+
+        for (; itr_TypeMap != TypeMap.end() && itr_TypeMapDB != TypeMapDB.end();
+             ++itr_TypeMap, ++itr_TypeMapDB) {
+            ASSERT_EQ(itr_TypeMap->first, itr_TypeMapDB->first)
+                    << "Invalid CodecMap data. type mismatch";
+            bool flag = compareMap(itr_TypeMap->second, itr_TypeMapDB->second);
+            ASSERT_TRUE(flag) << "typeMap mismatch";
+        }
+        ASSERT_EQ(mInputDataVector.at(index).codecProp.rank, properties.rank)
+                << "Invalid CodecMap data. rank mismatch";
+    }
+}
+
+TEST_F(XMLParseTest, RoleMapParseTest) {
+    string inputFileName = gEnv->getRes() + XML_FILE_NAME;
+    mEleStream.open(inputFileName, ifstream::binary);
+    ASSERT_EQ(mEleStream.is_open(), true) << "Failed to open inputfile " << inputFileName;
+
+    mParser.parseXmlPath(inputFileName);
+
+    for (auto &mRole : mParser.getRoleMap()) {
+        typedef pair<string, string> Attribute;
+        const string &roleName = mRole.first;
+        ALOGV("Role map:name = %s\n", roleName.c_str());
+        const MediaCodecsXmlParser::RoleProperties &properties = mRole.second;
+        string type = properties.type;
+        ALOGV("Role map: type = %s\n", type.c_str());
+
+        bool isEncoder = properties.isEncoder;
+        ALOGV("Role map: isEncoder = %d\n", isEncoder);
+
+        multimap<size_t, MediaCodecsXmlParser::NodeInfo> nodeList = properties.nodeList;
+        multimap<size_t, MediaCodecsXmlParser::NodeInfo>::iterator itr_Node;
+        ALOGV("\nThe multimap nodeList is : \n");
+        for (itr_Node = nodeList.begin(); itr_Node != nodeList.end(); ++itr_Node) {
+            ALOGV("itr_Node->first=ORDER=\t%zu\t", itr_Node->first);
+            int32_t index = itr_Node->first - 1;
+            MediaCodecsXmlParser::NodeInfo nodePtr = itr_Node->second;
+            ALOGV("Role map:itr_Node->second.name = %s\n", nodePtr.name.c_str());
+            vector<Attribute> attrList = nodePtr.attributeList;
+            for (auto attrNameValueList = attrList.begin(); attrNameValueList != attrList.end();
+                 ++attrNameValueList) {
+                ALOGV("Role map:nodePtr.attributeList->first = %s\n",
+                      attrNameValueList->first.c_str());
+                ALOGV("Role map:nodePtr.attributeList->second = %s\n",
+                      attrNameValueList->second.c_str());
+            }
+            checkRoleMap(index, isEncoder, properties.type, nodePtr.name.c_str(), attrList);
+        }
+    }
+}
+
+TEST_F(XMLParseTest, ServiceAttributeMapParseTest) {
+    string inputFileName = gEnv->getRes() + XML_FILE_NAME;
+    mEleStream.open(inputFileName, ifstream::binary);
+    ASSERT_EQ(mEleStream.is_open(), true) << "Failed to open inputfile " << inputFileName;
+
+    mParser.parseXmlPath(inputFileName);
+    const auto serviceAttributeMap = mParser.getServiceAttributeMap();
+    for (const auto &attributePair : serviceAttributeMap) {
+        ALOGV("serviceAttribute.key = %s \t serviceAttribute.value = %s",
+              attributePair.first.c_str(), attributePair.second.c_str());
+    }
+    bool flag = compareMap(mInputServiceAttributeMap, serviceAttributeMap);
+    ASSERT_TRUE(flag) << "ServiceMapParseTest: typeMap mismatch";
+}
+
+int main(int argc, char **argv) {
+    gEnv = new XMLParserTestEnvironment();
+    ::testing::AddGlobalTestEnvironment(gEnv);
+    ::testing::InitGoogleTest(&argc, argv);
+    int status = gEnv->initFromOptions(argc, argv);
+    if (status == 0) {
+        status = RUN_ALL_TESTS();
+        ALOGD("XML Parser Test Result = %d\n", status);
+    }
+    return status;
+}
diff --git a/media/libstagefright/xmlparser/test/XMLParserTestEnvironment.h b/media/libstagefright/xmlparser/test/XMLParserTestEnvironment.h
new file mode 100644
index 0000000..61a09e6
--- /dev/null
+++ b/media/libstagefright/xmlparser/test/XMLParserTestEnvironment.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 __XML_PARSER_TEST_ENVIRONMENT_H__
+#define __XML_PARSER_TEST_ENVIRONMENT_H__
+
+#include <gtest/gtest.h>
+
+#include <getopt.h>
+
+using namespace std;
+
+class XMLParserTestEnvironment : public ::testing::Environment {
+  public:
+    XMLParserTestEnvironment() : 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 XMLParserTestEnvironment::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  // __XML_PARSER_TEST_ENVIRONMENT_H__
diff --git a/media/libstagefright/xmlparser/test/testdata/media_codecs_unit_test.xml b/media/libstagefright/xmlparser/test/testdata/media_codecs_unit_test.xml
new file mode 100644
index 0000000..a7299d3
--- /dev/null
+++ b/media/libstagefright/xmlparser/test/testdata/media_codecs_unit_test.xml
@@ -0,0 +1,80 @@
+<?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.
+-->
+
+<!-- REFERENCE : frameworks/av/media/libstagefright/xmlparser/media_codecs.xsd -->
+<Included>
+    <Settings>
+        <Domain name="telephony" enabled="false" />
+        <Domain name="tv" enabled="false" />
+        <Variant name="variant1" enabled="false" />
+        <Setting name="setting1" value="settingValue1" update="true" />
+        <Setting name="setting2" enabled="false" />
+    </Settings>
+    <Decoders>
+        <!-- entry for enabled, domain, rank and update properties -->
+        <MediaCodec name="test1.decoder" type="audio/mpeg" update="false" domain="telephony" enabled="false" rank="4">
+            <Alias name="alias1.decoder" />
+            <Quirk name="quirk1" value="quirk1Value"/>
+        </MediaCodec>
+        <!-- entry for testing Quirk -->
+        <MediaCodec name="test2.decoder" type="audio/3gpp" enabled="true" >
+            <Quirk name="quirk1" value="quirk1Value"/>
+        </MediaCodec>
+        <!-- entry for testing Feature -->
+        <!-- feature2 takes value 0 (feature with same name takes lower feature's value) -->
+        <!-- feature3 gives value as 0 since it's optional -->
+        <!-- optional="true" required="true" is not a valid combination. -->
+        <!-- optional="false" required="false" is not a valid combination. -->
+        <MediaCodec name="test3.decoder" type="audio/amr-wb" >
+            <Feature name="feature1" value="feature1Val" />
+            <Feature name="feature2" value="feature2Val"/>
+            <Feature name="feature2" />
+            <Feature name="feature3" optional="true" required="false" />
+        </MediaCodec>
+        <!-- entry for testing Type -->
+        <MediaCodec name="test4.decoder">
+            <Type name="audio/flac">
+                <Feature name="feature1" value="feature1Val" />
+            </Type>
+        </MediaCodec>
+        <!-- entry for testing Attribute -->
+        <MediaCodec name="test5.decoder" type="audio/g711-mlaw" >
+            <Attribute name="attributeQuirk1" />
+        </MediaCodec>
+        <!-- entry for testing Variant -->
+        <MediaCodec name="test6.decoder" type="audio/mp4a-latm" variant="variant1,variant2" >
+            <Variant name="variant1">
+                <Limit name="variant1Limit1" min="variant1Limit1Min" max="variant1Limit1Max" />
+                <Limit name="variant1Limit2" range="variant1Limit2Low-variant1Limit2High" />
+            </Variant>
+            <Variant name="variant2">
+                <Limit name="variant2Limit1" value="variant2Limit1Value" />
+            </Variant>
+        </MediaCodec>
+        <!-- entry for testing Limit -->
+        <!-- 'in' is present in xsd file but not handled in MediaCodecsXmlParser -->
+        <MediaCodec name="test7.decoder" type="audio/vorbis" >
+            <Limit name="limit1" in="limit1In" min="limit1Min"/>
+            <Limit name="limit2" min="limit2Min" max="limit2Max" scale="limit2Scale" />
+            <Limit name="limit3" ranges="limit3Val1,limit3Val2,limit3Val3" default="limit3Val3" />
+        </MediaCodec>
+    </Decoders>
+    <Encoders>
+        <MediaCodec name="test8.encoder" type="audio/opus">
+            <Limit name="limit1" max="limit1Max" />
+        </MediaCodec>
+    </Encoders>
+</Included>
diff --git a/media/libstagefright/xmlparser/test/testdata/media_codecs_unit_test_caller.xml b/media/libstagefright/xmlparser/test/testdata/media_codecs_unit_test_caller.xml
new file mode 100644
index 0000000..d864ce9
--- /dev/null
+++ b/media/libstagefright/xmlparser/test/testdata/media_codecs_unit_test_caller.xml
@@ -0,0 +1,4 @@
+<!-- entry for testing Include -->
+<MediaCodecs>
+    <Include href="media_codecs_unit_test.xml" />
+</MediaCodecs>
diff --git a/media/ndk/Android.bp b/media/ndk/Android.bp
index a04a962..1893d28 100644
--- a/media/ndk/Android.bp
+++ b/media/ndk/Android.bp
@@ -71,6 +71,7 @@
     ],
 
     header_libs: [
+        "jni_headers",
         "libmediadrm_headers",
         "libmediametrics_headers",
     ],
@@ -98,6 +99,8 @@
         "libnativehelper",
     ],
 
+    export_header_lib_headers: ["jni_headers"],
+
     export_include_dirs: ["include"],
 
     export_shared_lib_headers: [
diff --git a/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/Encoder.java b/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/Encoder.java
index 45e5574..754cd8e 100644
--- a/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/Encoder.java
+++ b/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/Encoder.java
@@ -175,10 +175,10 @@
 
                 @Override
                 public void onError(@NonNull MediaCodec mediaCodec, @NonNull CodecException e) {
-                    mediaCodec.stop();
-                    mediaCodec.release();
-                    Log.e(TAG, "CodecError: " + e.toString());
+                    mSignalledError = true;
+                    Log.e(TAG, "Codec Error: " + e.toString());
                     e.printStackTrace();
+                    synchronized (mLock) { mLock.notify(); }
                 }
 
                 @Override
diff --git a/media/tests/benchmark/src/native/decoder/C2Decoder.cpp b/media/tests/benchmark/src/native/decoder/C2Decoder.cpp
index 20a1468..46c4a7c 100644
--- a/media/tests/benchmark/src/native/decoder/C2Decoder.cpp
+++ b/media/tests/benchmark/src/native/decoder/C2Decoder.cpp
@@ -156,9 +156,11 @@
     mStats->setDeInitTime(timeTaken);
 }
 
-void C2Decoder::dumpStatistics(string inputReference, int64_t durationUs) {
+void C2Decoder::dumpStatistics(string inputReference, int64_t durationUs, string componentName,
+                               string statsFile) {
     string operation = "c2decode";
-    mStats->dumpStatistics(operation, inputReference, durationUs);
+    string mode = "async";
+    mStats->dumpStatistics(operation, inputReference, durationUs, componentName, mode, statsFile);
 }
 
 void C2Decoder::resetDecoder() {
diff --git a/media/tests/benchmark/src/native/decoder/C2Decoder.h b/media/tests/benchmark/src/native/decoder/C2Decoder.h
index 4a3eb96..fb35a66 100644
--- a/media/tests/benchmark/src/native/decoder/C2Decoder.h
+++ b/media/tests/benchmark/src/native/decoder/C2Decoder.h
@@ -31,7 +31,8 @@
 
     void deInitCodec();
 
-    void dumpStatistics(string inputReference, int64_t durationUs);
+    void dumpStatistics(string inputReference, int64_t durationUs, string componentName,
+                        string statsFile);
 
     void resetDecoder();
 
diff --git a/media/tests/benchmark/src/native/encoder/C2Encoder.cpp b/media/tests/benchmark/src/native/encoder/C2Encoder.cpp
index 33429ef..6a50d40 100644
--- a/media/tests/benchmark/src/native/encoder/C2Encoder.cpp
+++ b/media/tests/benchmark/src/native/encoder/C2Encoder.cpp
@@ -251,9 +251,11 @@
     mStats->setDeInitTime(timeTaken);
 }
 
-void C2Encoder::dumpStatistics(string inputReference, int64_t durationUs) {
+void C2Encoder::dumpStatistics(string inputReference, int64_t durationUs, string componentName,
+                               string statsFile) {
     string operation = "c2encode";
-    mStats->dumpStatistics(operation, inputReference, durationUs);
+    string mode = "async";
+    mStats->dumpStatistics(operation, inputReference, durationUs, componentName, mode, statsFile);
 }
 
 void C2Encoder::resetEncoder() {
diff --git a/media/tests/benchmark/src/native/encoder/C2Encoder.h b/media/tests/benchmark/src/native/encoder/C2Encoder.h
index a4ca097..7a021f4 100644
--- a/media/tests/benchmark/src/native/encoder/C2Encoder.h
+++ b/media/tests/benchmark/src/native/encoder/C2Encoder.h
@@ -44,7 +44,8 @@
 
     void deInitCodec();
 
-    void dumpStatistics(string inputReference, int64_t durationUs);
+    void dumpStatistics(string inputReference, int64_t durationUs, string componentName,
+                        string statsFile);
 
     void resetEncoder();
 
diff --git a/media/tests/benchmark/tests/BenchmarkTestEnvironment.h b/media/tests/benchmark/tests/BenchmarkTestEnvironment.h
index ae2eee1..4edb048 100644
--- a/media/tests/benchmark/tests/BenchmarkTestEnvironment.h
+++ b/media/tests/benchmark/tests/BenchmarkTestEnvironment.h
@@ -25,7 +25,9 @@
 
 class BenchmarkTestEnvironment : public ::testing::Environment {
   public:
-    BenchmarkTestEnvironment() : res("/sdcard/media/") {}
+    BenchmarkTestEnvironment()
+        : res("/data/local/tmp/MediaBenchmark/res/"),
+          statsFile("/data/local/tmp/MediaBenchmark/res/stats.csv") {}
 
     // Parses the command line argument
     int initFromOptions(int argc, char **argv);
@@ -34,8 +36,15 @@
 
     const string getRes() const { return res; }
 
+    void setStatsFile(const string module) { statsFile = getRes() + module; }
+
+    const string getStatsFile() const { return statsFile; }
+
+    bool writeStatsHeader();
+
   private:
     string res;
+    string statsFile;
 };
 
 int BenchmarkTestEnvironment::initFromOptions(int argc, char **argv) {
@@ -70,4 +79,26 @@
     return 0;
 }
 
+/**
+ * Writes the stats header to a file
+ * <p>
+ * \param statsFile    file where the stats data is to be written
+ **/
+bool BenchmarkTestEnvironment::writeStatsHeader() {
+    char statsHeader[] =
+        "currentTime, fileName, operation, componentName, NDK/SDK, sync/async, setupTime, "
+        "destroyTime, minimumTime, maximumTime, averageTime, timeToProcess1SecContent, "
+        "totalBytesProcessedPerSec, timeToFirstFrame, totalSizeInBytes, totalTime\n";
+    FILE *fpStats = fopen(statsFile.c_str(), "w");
+    if(!fpStats) {
+        return false;
+    }
+    int32_t numBytes = fwrite(statsHeader, sizeof(char), sizeof(statsHeader), fpStats);
+    fclose(fpStats);
+    if(numBytes != sizeof(statsHeader)) {
+        return false;
+    }
+    return true;
+}
+
 #endif  // __BENCHMARK_TEST_ENVIRONMENT_H__
diff --git a/media/tests/benchmark/tests/C2DecoderTest.cpp b/media/tests/benchmark/tests/C2DecoderTest.cpp
index dedc743..85dcbc1 100644
--- a/media/tests/benchmark/tests/C2DecoderTest.cpp
+++ b/media/tests/benchmark/tests/C2DecoderTest.cpp
@@ -136,7 +136,8 @@
                 mDecoder->deInitCodec();
                 int64_t durationUs = extractor->getClipDuration();
                 ALOGV("codec : %s", codecName.c_str());
-                mDecoder->dumpStatistics(GetParam().first, durationUs);
+                mDecoder->dumpStatistics(GetParam().first, durationUs, codecName,
+                                         gEnv->getStatsFile());
                 mDecoder->resetDecoder();
             }
         }
@@ -178,6 +179,9 @@
     ::testing::InitGoogleTest(&argc, argv);
     int status = gEnv->initFromOptions(argc, argv);
     if (status == 0) {
+        gEnv->setStatsFile("C2Decoder.csv");
+        status = gEnv->writeStatsHeader();
+        ALOGV("Stats file = %d\n", status);
         status = RUN_ALL_TESTS();
         ALOGV("C2 Decoder Test result = %d\n", status);
     }
diff --git a/media/tests/benchmark/tests/C2EncoderTest.cpp b/media/tests/benchmark/tests/C2EncoderTest.cpp
index 98eb17a..b18d856 100644
--- a/media/tests/benchmark/tests/C2EncoderTest.cpp
+++ b/media/tests/benchmark/tests/C2EncoderTest.cpp
@@ -108,7 +108,7 @@
         }
 
         string decName = "";
-        string outputFileName = "decode.out";
+        string outputFileName = "/data/local/tmp/decode.out";
         FILE *outFp = fopen(outputFileName.c_str(), "wb");
         ASSERT_NE(outFp, nullptr) << "Unable to open output file" << outputFileName
                                   << " for dumping decoder's output";
@@ -140,7 +140,8 @@
                 mEncoder->deInitCodec();
                 int64_t durationUs = extractor->getClipDuration();
                 ALOGV("codec : %s", codecName.c_str());
-                mEncoder->dumpStatistics(GetParam().first, durationUs);
+                mEncoder->dumpStatistics(GetParam().first, durationUs, codecName,
+                                         gEnv->getStatsFile());
                 mEncoder->resetEncoder();
             }
         }
@@ -180,6 +181,9 @@
     ::testing::InitGoogleTest(&argc, argv);
     int status = gEnv->initFromOptions(argc, argv);
     if (status == 0) {
+        gEnv->setStatsFile("C2Encoder.csv");
+        status = gEnv->writeStatsHeader();
+        ALOGV("Stats file = %d\n", status);
         status = RUN_ALL_TESTS();
         ALOGV("C2 Encoder Test result = %d\n", status);
     }
diff --git a/media/tests/benchmark/tests/DecoderTest.cpp b/media/tests/benchmark/tests/DecoderTest.cpp
index 9f96d3b..81ef02a 100644
--- a/media/tests/benchmark/tests/DecoderTest.cpp
+++ b/media/tests/benchmark/tests/DecoderTest.cpp
@@ -84,7 +84,8 @@
         decoder->deInitCodec();
         ALOGV("codec : %s", codecName.c_str());
         string inputReference = get<0>(params);
-        decoder->dumpStatistics(inputReference);
+        decoder->dumpStatistics(inputReference, codecName, (asyncMode ? "async" : "sync"),
+                                gEnv->getStatsFile());
         free(inputBuffer);
         decoder->resetDecoder();
     }
@@ -179,8 +180,11 @@
     ::testing::InitGoogleTest(&argc, argv);
     int status = gEnv->initFromOptions(argc, argv);
     if (status == 0) {
+        gEnv->setStatsFile("Decoder.csv");
+        status = gEnv->writeStatsHeader();
+        ALOGV("Stats file = %d\n", status);
         status = RUN_ALL_TESTS();
-        ALOGD("Decoder Test result = %d\n", status);
+        ALOGV("Decoder Test result = %d\n", status);
     }
     return status;
 }
\ No newline at end of file
diff --git a/media/tests/benchmark/tests/EncoderTest.cpp b/media/tests/benchmark/tests/EncoderTest.cpp
index dc2a2dd..faac847 100644
--- a/media/tests/benchmark/tests/EncoderTest.cpp
+++ b/media/tests/benchmark/tests/EncoderTest.cpp
@@ -78,7 +78,7 @@
         }
 
         string decName = "";
-        string outputFileName = "decode.out";
+        string outputFileName = "/data/local/tmp/decode.out";
         FILE *outFp = fopen(outputFileName.c_str(), "wb");
         ASSERT_NE(outFp, nullptr) << "Unable to open output file" << outputFileName
                                   << " for dumping decoder's output";
@@ -133,7 +133,8 @@
         encoder->deInitCodec();
         ALOGV("codec : %s", codecName.c_str());
         string inputReference = get<0>(params);
-        encoder->dumpStatistics(inputReference, extractor->getClipDuration());
+        encoder->dumpStatistics(inputReference, extractor->getClipDuration(), codecName,
+                                (asyncMode ? "async" : "sync"), gEnv->getStatsFile());
         eleStream.close();
         if (outFp) fclose(outFp);
 
@@ -214,8 +215,11 @@
     ::testing::InitGoogleTest(&argc, argv);
     int status = gEnv->initFromOptions(argc, argv);
     if (status == 0) {
+        gEnv->setStatsFile("Encoder.csv");
+        status = gEnv->writeStatsHeader();
+        ALOGV("Stats file = %d\n", status);
         status = RUN_ALL_TESTS();
-        ALOGD("Encoder Test result = %d\n", status);
+        ALOGV("Encoder Test result = %d\n", status);
     }
     return status;
 }
diff --git a/media/tests/benchmark/tests/ExtractorTest.cpp b/media/tests/benchmark/tests/ExtractorTest.cpp
index ad8f1e6..d14d15b 100644
--- a/media/tests/benchmark/tests/ExtractorTest.cpp
+++ b/media/tests/benchmark/tests/ExtractorTest.cpp
@@ -48,8 +48,7 @@
     ASSERT_EQ(status, AMEDIA_OK) << "Extraction failed \n";
 
     extractObj->deInitExtractor();
-
-    extractObj->dumpStatistics(GetParam().first);
+    extractObj->dumpStatistics(GetParam().first, "", gEnv->getStatsFile());
 
     fclose(inputFp);
     delete extractObj;
@@ -79,8 +78,11 @@
     ::testing::InitGoogleTest(&argc, argv);
     int status = gEnv->initFromOptions(argc, argv);
     if (status == 0) {
+        gEnv->setStatsFile("Extractor.csv");
+        status = gEnv->writeStatsHeader();
+        ALOGV("Stats file = %d\n", status);
         status = RUN_ALL_TESTS();
-        ALOGD(" Extractor Test result = %d\n", status);
+        ALOGV("Extractor Test result = %d\n", status);
     }
     return status;
 }
diff --git a/media/tests/benchmark/tests/MuxerTest.cpp b/media/tests/benchmark/tests/MuxerTest.cpp
index fa2635d..991644b 100644
--- a/media/tests/benchmark/tests/MuxerTest.cpp
+++ b/media/tests/benchmark/tests/MuxerTest.cpp
@@ -113,7 +113,7 @@
         ASSERT_EQ(status, 0) << "Mux failed";
 
         muxerObj->deInitMuxer();
-        muxerObj->dumpStatistics(GetParam().first + "." + fmt.c_str());
+        muxerObj->dumpStatistics(GetParam().first + "." + fmt.c_str(), fmt, gEnv->getStatsFile());
         free(inputBuffer);
         fclose(outputFp);
         muxerObj->resetMuxer();
@@ -151,8 +151,11 @@
     ::testing::InitGoogleTest(&argc, argv);
     int status = gEnv->initFromOptions(argc, argv);
     if (status == 0) {
+        gEnv->setStatsFile("Muxer.csv");
+        status = gEnv->writeStatsHeader();
+        ALOGV("Stats file = %d\n", status);
         status = RUN_ALL_TESTS();
-        ALOGV("Test result = %d\n", status);
+        ALOGV("Muxer Test result = %d\n", status);
     }
     return status;
 }
diff --git a/services/audioflinger/FastThread.cpp b/services/audioflinger/FastThread.cpp
index 8b7a124..47fe0b3 100644
--- a/services/audioflinger/FastThread.cpp
+++ b/services/audioflinger/FastThread.cpp
@@ -309,7 +309,7 @@
                     // compute the delta value of clock_gettime(CLOCK_MONOTONIC)
                     uint32_t monotonicNs = nsec;
                     if (sec > 0 && sec < 4) {
-                        monotonicNs += sec * 1000000000;
+                        monotonicNs += sec * 1000000000U; // unsigned to prevent signed overflow.
                     }
                     // compute raw CPU load = delta value of clock_gettime(CLOCK_THREAD_CPUTIME_ID)
                     uint32_t loadNs = 0;
@@ -325,7 +325,7 @@
                             }
                             loadNs = nsec;
                             if (sec > 0 && sec < 4) {
-                                loadNs += sec * 1000000000;
+                                loadNs += sec * 1000000000U; // unsigned to prevent signed overflow.
                             }
                         } else {
                             // first time through the loop
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index 23d8329..bc33fd0 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -1915,6 +1915,25 @@
 {
     mProxy->releaseBuffer(buffer);
     restartIfDisabled();
+
+    // Check if the PatchTrack has enough data to write once in releaseBuffer().
+    // If not, prevent an underrun from occurring by moving the track into FS_FILLING;
+    // this logic avoids glitches when suspending A2DP with AudioPlaybackCapture.
+    // TODO: perhaps underrun avoidance could be a track property checked in isReady() instead.
+    if (mFillingUpStatus == FS_ACTIVE
+            && audio_is_linear_pcm(mFormat)
+            && !isOffloadedOrDirect()) {
+        if (sp<ThreadBase> thread = mThread.promote();
+            thread != 0) {
+            PlaybackThread *playbackThread = (PlaybackThread *)thread.get();
+            const size_t frameCount = playbackThread->frameCount() * sampleRate()
+                    / playbackThread->sampleRate();
+            if (framesReady() < frameCount) {
+                ALOGD("%s(%d) Not enough data, wait for buffer to fill", __func__, mId);
+                mFillingUpStatus = FS_FILLING;
+            }
+        }
+    }
 }
 
 void AudioFlinger::PlaybackThread::PatchTrack::restartIfDisabled()
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index f92d673..87f924b 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -794,7 +794,7 @@
 
 Status CameraService::makeClient(const sp<CameraService>& cameraService,
         const sp<IInterface>& cameraCb, const String16& packageName,
-        const std::unique_ptr<String16>& featureId, const String8& cameraId, int api1CameraId,
+        const std::optional<String16>& featureId, const String8& cameraId, int api1CameraId,
         int facing, int clientPid, uid_t clientUid, int servicePid, int halVersion,
         int deviceVersion, apiLevel effectiveApiLevel,
         /*out*/sp<BasicClient>* client) {
@@ -950,7 +950,7 @@
     if (!(ret = connectHelper<ICameraClient,Client>(
             sp<ICameraClient>{nullptr}, id, cameraId,
             static_cast<int>(CAMERA_HAL_API_VERSION_UNSPECIFIED),
-            internalPackageName, std::unique_ptr<String16>(), uid, USE_CALLING_PID,
+            internalPackageName, {}, uid, USE_CALLING_PID,
             API_1, /*shimUpdateOnly*/ true, /*out*/ tmp)
             ).isOk()) {
         ALOGE("%s: Error initializing shim metadata: %s", __FUNCTION__, ret.toString8().string());
@@ -1463,7 +1463,7 @@
     String8 id = cameraIdIntToStr(api1CameraId);
     sp<Client> client = nullptr;
     ret = connectHelper<ICameraClient,Client>(cameraClient, id, api1CameraId,
-            CAMERA_HAL_API_VERSION_UNSPECIFIED, clientPackageName, std::unique_ptr<String16>(),
+            CAMERA_HAL_API_VERSION_UNSPECIFIED, clientPackageName, {},
             clientUid, clientPid, API_1, /*shimUpdateOnly*/ false, /*out*/client);
 
     if(!ret.isOk()) {
@@ -1490,7 +1490,7 @@
     Status ret = Status::ok();
     sp<Client> client = nullptr;
     ret = connectHelper<ICameraClient,Client>(cameraClient, id, api1CameraId, halVersion,
-            clientPackageName, std::unique_ptr<String16>(), clientUid, USE_CALLING_PID, API_1,
+            clientPackageName, {}, clientUid, USE_CALLING_PID, API_1,
             /*shimUpdateOnly*/ false, /*out*/client);
 
     if(!ret.isOk()) {
@@ -1565,7 +1565,7 @@
         const sp<hardware::camera2::ICameraDeviceCallbacks>& cameraCb,
         const String16& cameraId,
         const String16& clientPackageName,
-        const std::unique_ptr<String16>& clientFeatureId,
+        const std::optional<String16>& clientFeatureId,
         int clientUid,
         /*out*/
         sp<hardware::camera2::ICameraDeviceUser>* device) {
@@ -1599,7 +1599,7 @@
 template<class CALLBACK, class CLIENT>
 Status CameraService::connectHelper(const sp<CALLBACK>& cameraCb, const String8& cameraId,
         int api1CameraId, int halVersion, const String16& clientPackageName,
-        const std::unique_ptr<String16>& clientFeatureId, int clientUid, int clientPid,
+        const std::optional<String16>& clientFeatureId, int clientUid, int clientPid,
         apiLevel effectiveApiLevel, bool shimUpdateOnly,
         /*out*/sp<CLIENT>& device) {
     binder::Status ret = binder::Status::ok();
@@ -2697,7 +2697,7 @@
 CameraService::Client::Client(const sp<CameraService>& cameraService,
         const sp<ICameraClient>& cameraClient,
         const String16& clientPackageName,
-        const std::unique_ptr<String16>& clientFeatureId,
+        const std::optional<String16>& clientFeatureId,
         const String8& cameraIdStr,
         int api1CameraId, int cameraFacing,
         int clientPid, uid_t clientUid,
@@ -2734,24 +2734,18 @@
 
 CameraService::BasicClient::BasicClient(const sp<CameraService>& cameraService,
         const sp<IBinder>& remoteCallback,
-        const String16& clientPackageName, const std::unique_ptr<String16>& clientFeatureId,
+        const String16& clientPackageName, const std::optional<String16>& clientFeatureId,
         const String8& cameraIdStr, int cameraFacing,
         int clientPid, uid_t clientUid,
         int servicePid):
         mCameraIdStr(cameraIdStr), mCameraFacing(cameraFacing),
-        mClientPackageName(clientPackageName),
+        mClientPackageName(clientPackageName), mClientFeatureId(clientFeatureId),
         mClientPid(clientPid), mClientUid(clientUid),
         mServicePid(servicePid),
         mDisconnected(false), mUidIsTrusted(false),
         mAudioRestriction(hardware::camera2::ICameraDeviceUser::AUDIO_RESTRICTION_NONE),
         mRemoteBinder(remoteCallback)
 {
-    if (clientFeatureId) {
-        mClientFeatureId = std::unique_ptr<String16>(new String16(*clientFeatureId));
-    } else {
-        mClientFeatureId = std::unique_ptr<String16>();
-    }
-
     if (sCameraService == nullptr) {
         sCameraService = cameraService;
     }
diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h
index 18cf77a..590f5eb 100644
--- a/services/camera/libcameraservice/CameraService.h
+++ b/services/camera/libcameraservice/CameraService.h
@@ -51,6 +51,7 @@
 #include <string>
 #include <map>
 #include <memory>
+#include <optional>
 #include <utility>
 #include <unordered_map>
 #include <unordered_set>
@@ -141,7 +142,7 @@
 
     virtual binder::Status     connectDevice(
             const sp<hardware::camera2::ICameraDeviceCallbacks>& cameraCb, const String16& cameraId,
-            const String16& clientPackageName, const std::unique_ptr<String16>& clientFeatureId,
+            const String16& clientPackageName, const std::optional<String16>& clientFeatureId,
             int32_t clientUid,
             /*out*/
             sp<hardware::camera2::ICameraDeviceUser>* device);
@@ -298,7 +299,7 @@
         BasicClient(const sp<CameraService>& cameraService,
                 const sp<IBinder>& remoteCallback,
                 const String16& clientPackageName,
-                const std::unique_ptr<String16>& clientFeatureId,
+                const std::optional<String16>& clientFeatureId,
                 const String8& cameraIdStr,
                 int cameraFacing,
                 int clientPid,
@@ -318,7 +319,7 @@
         const String8                   mCameraIdStr;
         const int                       mCameraFacing;
         String16                        mClientPackageName;
-        std::unique_ptr<String16>       mClientFeatureId;
+        std::optional<String16>         mClientFeatureId;
         pid_t                           mClientPid;
         const uid_t                     mClientUid;
         const pid_t                     mServicePid;
@@ -390,7 +391,7 @@
         Client(const sp<CameraService>& cameraService,
                 const sp<hardware::ICameraClient>& cameraClient,
                 const String16& clientPackageName,
-                const std::unique_ptr<String16>& clientFeatureId,
+                const std::optional<String16>& clientFeatureId,
                 const String8& cameraIdStr,
                 int api1CameraId,
                 int cameraFacing,
@@ -728,7 +729,7 @@
     template<class CALLBACK, class CLIENT>
     binder::Status connectHelper(const sp<CALLBACK>& cameraCb, const String8& cameraId,
             int api1CameraId, int halVersion, const String16& clientPackageName,
-            const std::unique_ptr<String16>& clientFeatureId, int clientUid, int clientPid,
+            const std::optional<String16>& clientFeatureId, int clientUid, int clientPid,
             apiLevel effectiveApiLevel, bool shimUpdateOnly, /*out*/sp<CLIENT>& device);
 
     // Lock guarding camera service state
@@ -1056,7 +1057,7 @@
 
     static binder::Status makeClient(const sp<CameraService>& cameraService,
             const sp<IInterface>& cameraCb, const String16& packageName,
-            const std::unique_ptr<String16>& featureId, const String8& cameraId, int api1CameraId,
+            const std::optional<String16>& featureId, const String8& cameraId, int api1CameraId,
             int facing, int clientPid, uid_t clientUid, int servicePid, int halVersion,
             int deviceVersion, apiLevel effectiveApiLevel,
             /*out*/sp<BasicClient>* client);
diff --git a/services/camera/libcameraservice/api1/Camera2Client.cpp b/services/camera/libcameraservice/api1/Camera2Client.cpp
index ebb0555..e01e86d 100644
--- a/services/camera/libcameraservice/api1/Camera2Client.cpp
+++ b/services/camera/libcameraservice/api1/Camera2Client.cpp
@@ -50,7 +50,7 @@
 Camera2Client::Camera2Client(const sp<CameraService>& cameraService,
         const sp<hardware::ICameraClient>& cameraClient,
         const String16& clientPackageName,
-        const std::unique_ptr<String16>& clientFeatureId,
+        const std::optional<String16>& clientFeatureId,
         const String8& cameraDeviceId,
         int api1CameraId,
         int cameraFacing,
diff --git a/services/camera/libcameraservice/api1/Camera2Client.h b/services/camera/libcameraservice/api1/Camera2Client.h
index 3144e0e..c5f0428 100644
--- a/services/camera/libcameraservice/api1/Camera2Client.h
+++ b/services/camera/libcameraservice/api1/Camera2Client.h
@@ -94,7 +94,7 @@
     Camera2Client(const sp<CameraService>& cameraService,
             const sp<hardware::ICameraClient>& cameraClient,
             const String16& clientPackageName,
-            const std::unique_ptr<String16>& clientFeatureId,
+            const std::optional<String16>& clientFeatureId,
             const String8& cameraDeviceId,
             int api1CameraId,
             int cameraFacing,
diff --git a/services/camera/libcameraservice/api1/CameraClient.cpp b/services/camera/libcameraservice/api1/CameraClient.cpp
index 892996c..b860ceb 100644
--- a/services/camera/libcameraservice/api1/CameraClient.cpp
+++ b/services/camera/libcameraservice/api1/CameraClient.cpp
@@ -34,7 +34,7 @@
 
 CameraClient::CameraClient(const sp<CameraService>& cameraService,
         const sp<hardware::ICameraClient>& cameraClient,
-        const String16& clientPackageName, const std::unique_ptr<String16>& clientFeatureId,
+        const String16& clientPackageName, const std::optional<String16>& clientFeatureId,
         int cameraId, int cameraFacing,
         int clientPid, int clientUid,
         int servicePid):
diff --git a/services/camera/libcameraservice/api1/CameraClient.h b/services/camera/libcameraservice/api1/CameraClient.h
index a7eb960..aacb00e 100644
--- a/services/camera/libcameraservice/api1/CameraClient.h
+++ b/services/camera/libcameraservice/api1/CameraClient.h
@@ -68,7 +68,7 @@
     CameraClient(const sp<CameraService>& cameraService,
             const sp<hardware::ICameraClient>& cameraClient,
             const String16& clientPackageName,
-            const std::unique_ptr<String16>& clientFeatureId,
+            const std::optional<String16>& clientFeatureId,
             int cameraId,
             int cameraFacing,
             int clientPid,
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
index e35b436..022d686 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
@@ -54,7 +54,7 @@
         const sp<CameraService>& cameraService,
         const sp<hardware::camera2::ICameraDeviceCallbacks>& remoteCallback,
         const String16& clientPackageName,
-        const std::unique_ptr<String16>& clientFeatureId,
+        const std::optional<String16>& clientFeatureId,
         const String8& cameraId,
         int api1CameraId,
         int cameraFacing,
@@ -80,7 +80,7 @@
 CameraDeviceClient::CameraDeviceClient(const sp<CameraService>& cameraService,
         const sp<hardware::camera2::ICameraDeviceCallbacks>& remoteCallback,
         const String16& clientPackageName,
-        const std::unique_ptr<String16>& clientFeatureId,
+        const std::optional<String16>& clientFeatureId,
         const String8& cameraId,
         int cameraFacing,
         int clientPid,
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.h b/services/camera/libcameraservice/api2/CameraDeviceClient.h
index 964c96a..e7e26da 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.h
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.h
@@ -50,7 +50,7 @@
     CameraDeviceClientBase(const sp<CameraService>& cameraService,
             const sp<hardware::camera2::ICameraDeviceCallbacks>& remoteCallback,
             const String16& clientPackageName,
-            const std::unique_ptr<String16>& clientFeatureId,
+            const std::optional<String16>& clientFeatureId,
             const String8& cameraId,
             int api1CameraId,
             int cameraFacing,
@@ -175,7 +175,7 @@
     CameraDeviceClient(const sp<CameraService>& cameraService,
             const sp<hardware::camera2::ICameraDeviceCallbacks>& remoteCallback,
             const String16& clientPackageName,
-            const std::unique_ptr<String16>& clientFeatureId,
+            const std::optional<String16>& clientFeatureId,
             const String8& cameraId,
             int cameraFacing,
             int clientPid,
diff --git a/services/camera/libcameraservice/api2/CameraOfflineSessionClient.h b/services/camera/libcameraservice/api2/CameraOfflineSessionClient.h
index b67fcb3..03621c8 100644
--- a/services/camera/libcameraservice/api2/CameraOfflineSessionClient.h
+++ b/services/camera/libcameraservice/api2/CameraOfflineSessionClient.h
@@ -48,7 +48,7 @@
             const KeyedVector<sp<IBinder>, sp<CompositeStream>>& offlineCompositeStreamMap,
             const sp<ICameraDeviceCallbacks>& remoteCallback,
             const String16& clientPackageName,
-            const std::unique_ptr<String16>& clientFeatureId,
+            const std::optional<String16>& clientFeatureId,
             const String8& cameraIdStr, int cameraFacing,
             int clientPid, uid_t clientUid, int servicePid) :
             CameraService::BasicClient(
diff --git a/services/camera/libcameraservice/common/Camera2ClientBase.cpp b/services/camera/libcameraservice/common/Camera2ClientBase.cpp
index 0a41776..609698c 100644
--- a/services/camera/libcameraservice/common/Camera2ClientBase.cpp
+++ b/services/camera/libcameraservice/common/Camera2ClientBase.cpp
@@ -44,7 +44,7 @@
         const sp<CameraService>& cameraService,
         const sp<TCamCallbacks>& remoteCallback,
         const String16& clientPackageName,
-        const std::unique_ptr<String16>& clientFeatureId,
+        const std::optional<String16>& clientFeatureId,
         const String8& cameraId,
         int api1CameraId,
         int cameraFacing,
diff --git a/services/camera/libcameraservice/common/Camera2ClientBase.h b/services/camera/libcameraservice/common/Camera2ClientBase.h
index 042f5aa..d7506af 100644
--- a/services/camera/libcameraservice/common/Camera2ClientBase.h
+++ b/services/camera/libcameraservice/common/Camera2ClientBase.h
@@ -48,7 +48,7 @@
     Camera2ClientBase(const sp<CameraService>& cameraService,
                       const sp<TCamCallbacks>& remoteCallback,
                       const String16& clientPackageName,
-                      const std::unique_ptr<String16>& clientFeatureId,
+                      const std::optional<String16>& clientFeatureId,
                       const String8& cameraId,
                       int api1CameraId,
                       int cameraFacing,
diff --git a/services/camera/libcameraservice/hidl/HidlCameraService.cpp b/services/camera/libcameraservice/hidl/HidlCameraService.cpp
index a46133e..9ea9526 100644
--- a/services/camera/libcameraservice/hidl/HidlCameraService.cpp
+++ b/services/camera/libcameraservice/hidl/HidlCameraService.cpp
@@ -103,7 +103,7 @@
     }
     sp<hardware::camera2::ICameraDeviceCallbacks> callbacks = hybridCallbacks;
     binder::Status serviceRet = mAidlICameraService->connectDevice(
-            callbacks, String16(cameraId.c_str()), String16(""), std::unique_ptr<String16>(),
+            callbacks, String16(cameraId.c_str()), String16(""), {},
             hardware::ICameraService::USE_CALLING_UID, /*out*/&deviceRemote);
     HStatus status = HStatus::NO_ERROR;
     if (!serviceRet.isOk()) {
diff --git a/services/mediaextractor/Android.bp b/services/mediaextractor/Android.bp
index 0b25d62..05b7d22 100644
--- a/services/mediaextractor/Android.bp
+++ b/services/mediaextractor/Android.bp
@@ -35,9 +35,6 @@
         "liblog",
         "libavservices_minijail",
     ],
-    header_libs: [
-        "bionic_libc_platform_headers",
-    ],
     target: {
         android: {
             product_variables: {
diff --git a/services/mediaextractor/MediaExtractorService.cpp b/services/mediaextractor/MediaExtractorService.cpp
index 9992d1c..71a5bff 100644
--- a/services/mediaextractor/MediaExtractorService.cpp
+++ b/services/mediaextractor/MediaExtractorService.cpp
@@ -39,23 +39,23 @@
 
 ::android::binder::Status MediaExtractorService::makeExtractor(
         const ::android::sp<::android::IDataSource>& remoteSource,
-        const ::std::unique_ptr< ::std::string> &mime,
+        const ::std::optional< ::std::string> &mime,
         ::android::sp<::android::IMediaExtractor>* _aidl_return) {
-    ALOGV("@@@ MediaExtractorService::makeExtractor for %s", mime.get()->c_str());
+    ALOGV("@@@ MediaExtractorService::makeExtractor for %s", mime ? mime->c_str() : nullptr);
 
     sp<DataSource> localSource = CreateDataSourceFromIDataSource(remoteSource);
 
     MediaBuffer::useSharedMemory();
     sp<IMediaExtractor> extractor = MediaExtractorFactory::CreateFromService(
             localSource,
-            mime.get() ? mime.get()->c_str() : nullptr);
+            mime ? mime->c_str() : nullptr);
 
     ALOGV("extractor service created %p (%s)",
             extractor.get(),
             extractor == nullptr ? "" : extractor->name());
 
     if (extractor != nullptr) {
-        registerMediaExtractor(extractor, localSource, mime.get() ? mime.get()->c_str() : nullptr);
+        registerMediaExtractor(extractor, localSource, mime ? mime->c_str() : nullptr);
     }
     *_aidl_return = extractor;
     return binder::Status::ok();
diff --git a/services/mediaextractor/MediaExtractorService.h b/services/mediaextractor/MediaExtractorService.h
index 1b40bf9..0081e7e 100644
--- a/services/mediaextractor/MediaExtractorService.h
+++ b/services/mediaextractor/MediaExtractorService.h
@@ -33,7 +33,7 @@
 
     virtual ::android::binder::Status makeExtractor(
             const ::android::sp<::android::IDataSource>& source,
-            const ::std::unique_ptr< ::std::string> &mime,
+            const ::std::optional< ::std::string> &mime,
             ::android::sp<::android::IMediaExtractor>* _aidl_return);
 
     virtual ::android::binder::Status makeIDataSource(
diff --git a/services/mediaextractor/main_extractorservice.cpp b/services/mediaextractor/main_extractorservice.cpp
index f21574f..b7b51a6 100644
--- a/services/mediaextractor/main_extractorservice.cpp
+++ b/services/mediaextractor/main_extractorservice.cpp
@@ -28,8 +28,6 @@
 #include <android-base/properties.h>
 #include <utils/misc.h>
 
-#include <bionic/reserved_signals.h>
-
 // from LOCAL_C_INCLUDES
 #include "MediaExtractorService.h"
 #include "minijail.h"
@@ -50,10 +48,6 @@
 
     signal(SIGPIPE, SIG_IGN);
 
-    // Do not assist platform profilers (relevant only on debug builds).
-    // Otherwise, the signal handler can violate the seccomp policy.
-    signal(BIONIC_SIGNAL_PROFILER, SIG_IGN);
-
     //b/62255959: this forces libutis.so to dlopen vendor version of libutils.so
     //before minijail is on. This is dirty but required since some syscalls such
     //as pread64 are used by linker but aren't allowed in the minijail. By
diff --git a/services/mediaresourcemanager/ResourceManagerService.h b/services/mediaresourcemanager/ResourceManagerService.h
index f500c62..92048c3 100644
--- a/services/mediaresourcemanager/ResourceManagerService.h
+++ b/services/mediaresourcemanager/ResourceManagerService.h
@@ -41,7 +41,7 @@
 using ::aidl::android::media::MediaResourcePolicyParcel;
 
 typedef std::map<std::tuple<
-        MediaResource::Type, MediaResource::SubType, std::vector<int8_t>>,
+        MediaResource::Type, MediaResource::SubType, std::vector<uint8_t>>,
         MediaResourceParcel> ResourceList;
 
 struct ResourceInfo {
diff --git a/services/oboeservice/SharedMemoryProxy.cpp b/services/oboeservice/SharedMemoryProxy.cpp
index c43ed22..78d4884 100644
--- a/services/oboeservice/SharedMemoryProxy.cpp
+++ b/services/oboeservice/SharedMemoryProxy.cpp
@@ -20,6 +20,7 @@
 
 #include <errno.h>
 #include <string.h>
+#include <unistd.h>
 
 #include <aaudio/AAudio.h>
 #include "SharedMemoryProxy.h"