Merge "Add a fuzzer for RecordBufferConverter."
diff --git a/media/libaudioprocessing/tests/fuzzer/Android.bp b/media/libaudioprocessing/tests/fuzzer/Android.bp
index 1df47b7..2a0dec4 100644
--- a/media/libaudioprocessing/tests/fuzzer/Android.bp
+++ b/media/libaudioprocessing/tests/fuzzer/Android.bp
@@ -8,3 +8,14 @@
     "libsndfile",
   ],
 }
+
+cc_fuzz {
+  name: "libaudioprocessing_record_buffer_converter_fuzzer",
+  srcs: [
+    "libaudioprocessing_record_buffer_converter_fuzzer.cpp",
+  ],
+  defaults: ["libaudioprocessing_test_defaults"],
+  static_libs: [
+    "libsndfile",
+  ],
+}
diff --git a/media/libaudioprocessing/tests/fuzzer/libaudioprocessing_fuzz_utils.h b/media/libaudioprocessing/tests/fuzzer/libaudioprocessing_fuzz_utils.h
new file mode 100644
index 0000000..5165925
--- /dev/null
+++ b/media/libaudioprocessing/tests/fuzzer/libaudioprocessing_fuzz_utils.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2021 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 ANDROID_LIBAUDIOPROCESSING_FUZZ_UTILS_H
+#define ANDROID_LIBAUDIOPROCESSING_FUZZ_UTILS_H
+
+#include <media/AudioBufferProvider.h>
+#include <system/audio.h>
+
+namespace android {
+
+class Provider : public AudioBufferProvider {
+  const void* mAddr;        // base address
+  const size_t mNumFrames;  // total frames
+  const size_t mFrameSize;  // size of each frame in bytes
+  size_t mNextFrame;        // index of next frame to provide
+  size_t mUnrel;            // number of frames not yet released
+ public:
+  Provider(const void* addr, size_t frames, size_t frameSize)
+      : mAddr(addr),
+        mNumFrames(frames),
+        mFrameSize(frameSize),
+        mNextFrame(0),
+        mUnrel(0) {}
+  status_t getNextBuffer(Buffer* buffer) override {
+    if (buffer->frameCount > mNumFrames - mNextFrame) {
+      buffer->frameCount = mNumFrames - mNextFrame;
+    }
+    mUnrel = buffer->frameCount;
+    if (buffer->frameCount > 0) {
+      buffer->raw = (char*)mAddr + mFrameSize * mNextFrame;
+      return NO_ERROR;
+    } else {
+      buffer->raw = nullptr;
+      return NOT_ENOUGH_DATA;
+    }
+  }
+  void releaseBuffer(Buffer* buffer) override {
+    if (buffer->frameCount > mUnrel) {
+      mNextFrame += mUnrel;
+      mUnrel = 0;
+    } else {
+      mNextFrame += buffer->frameCount;
+      mUnrel -= buffer->frameCount;
+    }
+    buffer->frameCount = 0;
+    buffer->raw = nullptr;
+  }
+  void reset() { mNextFrame = 0; }
+};
+
+} // namespace android
+
+#endif // ANDROID_LIBAUDIOPROCESSING_FUZZ_UTILS_H
diff --git a/media/libaudioprocessing/tests/fuzzer/libaudioprocessing_record_buffer_converter_fuzzer.cpp b/media/libaudioprocessing/tests/fuzzer/libaudioprocessing_record_buffer_converter_fuzzer.cpp
new file mode 100644
index 0000000..017598c
--- /dev/null
+++ b/media/libaudioprocessing/tests/fuzzer/libaudioprocessing_record_buffer_converter_fuzzer.cpp
@@ -0,0 +1,177 @@
+/*
+ * 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 "libaudioprocessing_fuzz_utils.h"
+#include "fuzzer/FuzzedDataProvider.h"
+#include <media/AudioResampler.h>
+#include <media/RecordBufferConverter.h>
+#include <stddef.h>
+#include <stdint.h>
+
+using namespace android;
+
+constexpr int MAX_FRAMES = 1024;
+
+#define AUDIO_FORMAT_PCM_MAIN 0
+
+// Copied and simplified from audio-hal-enums.h?l=571
+constexpr uint32_t FUZZ_AUDIO_FORMATS[] = {
+  AUDIO_FORMAT_PCM_MAIN | AUDIO_FORMAT_PCM_SUB_16_BIT,
+  AUDIO_FORMAT_PCM_MAIN | AUDIO_FORMAT_PCM_SUB_8_BIT,
+  AUDIO_FORMAT_PCM_MAIN | AUDIO_FORMAT_PCM_SUB_32_BIT,
+  AUDIO_FORMAT_PCM_MAIN | AUDIO_FORMAT_PCM_SUB_8_24_BIT,
+  AUDIO_FORMAT_PCM_MAIN | AUDIO_FORMAT_PCM_SUB_FLOAT,
+  AUDIO_FORMAT_PCM_MAIN | AUDIO_FORMAT_PCM_SUB_24_BIT_PACKED,
+  0x01000000u,
+  0x02000000u,
+  0x03000000u,
+  0x04000000u,
+  AUDIO_FORMAT_AAC | AUDIO_FORMAT_AAC_SUB_MAIN,
+  AUDIO_FORMAT_AAC | AUDIO_FORMAT_AAC_SUB_LC,
+  AUDIO_FORMAT_AAC | AUDIO_FORMAT_AAC_SUB_SSR,
+  AUDIO_FORMAT_AAC | AUDIO_FORMAT_AAC_SUB_LTP,
+  AUDIO_FORMAT_AAC | AUDIO_FORMAT_AAC_SUB_HE_V1,
+  AUDIO_FORMAT_AAC | AUDIO_FORMAT_AAC_SUB_SCALABLE,
+  AUDIO_FORMAT_AAC | AUDIO_FORMAT_AAC_SUB_ERLC,
+  AUDIO_FORMAT_AAC | AUDIO_FORMAT_AAC_SUB_LD,
+  AUDIO_FORMAT_AAC | AUDIO_FORMAT_AAC_SUB_HE_V2,
+  AUDIO_FORMAT_AAC | AUDIO_FORMAT_AAC_SUB_ELD,
+  AUDIO_FORMAT_AAC | AUDIO_FORMAT_AAC_SUB_XHE,
+  0x05000000u,
+  0x06000000u,
+  0x07000000u,
+  0x08000000u,
+  0x09000000u,
+  0x0A000000u,
+  AUDIO_FORMAT_E_AC3 | AUDIO_FORMAT_E_AC3_SUB_JOC,
+  0x0B000000u,
+  0x0C000000u,
+  0x0D000000u,
+  0x0E000000u,
+  0x10000000u,
+  0x11000000u,
+  0x12000000u,
+  0x13000000u,
+  0x14000000u,
+  0x15000000u,
+  0x16000000u,
+  0x17000000u,
+  0x18000000u,
+  0x19000000u,
+  0x1A000000u,
+  0x1B000000u,
+  0x1C000000u,
+  0x1D000000u,
+  0x1E000000u,
+  AUDIO_FORMAT_AAC_ADTS | AUDIO_FORMAT_AAC_SUB_MAIN,
+  AUDIO_FORMAT_AAC_ADTS | AUDIO_FORMAT_AAC_SUB_LC,
+  AUDIO_FORMAT_AAC_ADTS | AUDIO_FORMAT_AAC_SUB_SSR,
+  AUDIO_FORMAT_AAC_ADTS | AUDIO_FORMAT_AAC_SUB_LTP,
+  AUDIO_FORMAT_AAC_ADTS | AUDIO_FORMAT_AAC_SUB_HE_V1,
+  AUDIO_FORMAT_AAC_ADTS | AUDIO_FORMAT_AAC_SUB_SCALABLE,
+  AUDIO_FORMAT_AAC_ADTS | AUDIO_FORMAT_AAC_SUB_ERLC,
+  AUDIO_FORMAT_AAC_ADTS | AUDIO_FORMAT_AAC_SUB_LD,
+  AUDIO_FORMAT_AAC_ADTS | AUDIO_FORMAT_AAC_SUB_HE_V2,
+  AUDIO_FORMAT_AAC_ADTS | AUDIO_FORMAT_AAC_SUB_ELD,
+  AUDIO_FORMAT_AAC_ADTS | AUDIO_FORMAT_AAC_SUB_XHE,
+  0x1F000000u,
+  0x20000000u,
+  0x21000000u,
+  0x22000000u,
+  0x23000000u,
+  0x24000000u,
+  AUDIO_FORMAT_MAT | AUDIO_FORMAT_MAT_SUB_1_0,
+  AUDIO_FORMAT_MAT | AUDIO_FORMAT_MAT_SUB_2_0,
+  AUDIO_FORMAT_MAT | AUDIO_FORMAT_MAT_SUB_2_1,
+  0x25000000u,
+  AUDIO_FORMAT_AAC_LATM | AUDIO_FORMAT_AAC_SUB_LC,
+  AUDIO_FORMAT_AAC_LATM | AUDIO_FORMAT_AAC_SUB_HE_V1,
+  AUDIO_FORMAT_AAC_LATM | AUDIO_FORMAT_AAC_SUB_HE_V2,
+  0x26000000u,
+  0x27000000u,
+  0x28000000u,
+  0x29000000u,
+  0x2A000000u,
+  0x2B000000u,
+  0xFFFFFFFFu,
+  AUDIO_FORMAT_PCM_MAIN,
+  AUDIO_FORMAT_PCM,
+};
+constexpr size_t NUM_AUDIO_FORMATS = std::size(FUZZ_AUDIO_FORMATS);
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+  FuzzedDataProvider fdp(data, size);
+  fdp.ConsumeIntegral<int>();
+
+  const audio_channel_mask_t srcChannelMask = (audio_channel_mask_t)fdp.ConsumeIntegral<int>();
+  const audio_format_t srcFormat =
+      (audio_format_t)FUZZ_AUDIO_FORMATS[fdp.ConsumeIntegralInRange<int>(0, NUM_AUDIO_FORMATS - 1)];
+  const uint32_t srcSampleRate = fdp.ConsumeIntegralInRange<int>(1, 0x7fffffff);
+  const audio_channel_mask_t dstChannelMask = (audio_channel_mask_t)fdp.ConsumeIntegral<int>();
+  const audio_format_t dstFormat =
+      (audio_format_t)FUZZ_AUDIO_FORMATS[fdp.ConsumeIntegralInRange<int>(0, NUM_AUDIO_FORMATS - 1)];
+  const uint32_t dstSampleRate = fdp.ConsumeIntegralInRange<int>(1, 0x7fffffff);
+
+  // Certain formats will result in LOG_ALWAYS_FATAL errors that aren't interesting crashes
+  // for fuzzing.  Don't use those ones.
+  const uint32_t dstChannelCount = audio_channel_count_from_in_mask(dstChannelMask);
+  constexpr android::AudioResampler::src_quality quality =
+      android::AudioResampler::DEFAULT_QUALITY;
+  const int maxChannels =
+      quality < android::AudioResampler::DYN_LOW_QUALITY ? 2 : 8;
+  if (dstChannelCount < 1 || dstChannelCount > maxChannels) {
+    return 0;
+  }
+
+  const uint32_t srcChannelCount = audio_channel_count_from_in_mask(srcChannelMask);
+  if (srcChannelCount < 1 || srcChannelCount > maxChannels) {
+    return 0;
+  }
+
+  RecordBufferConverter converter(srcChannelMask, srcFormat, srcSampleRate,
+                                  dstChannelMask, dstFormat, dstSampleRate);
+  if (converter.initCheck() != NO_ERROR) {
+    return 0;
+  }
+
+  const uint32_t srcFrameSize = srcChannelCount * audio_bytes_per_sample(srcFormat);
+  const int srcNumFrames = fdp.ConsumeIntegralInRange<int>(0, MAX_FRAMES);
+  constexpr size_t metadataSize = 2 + 3 * sizeof(int) + 2 * sizeof(float);
+  std::vector<uint8_t> inputData = fdp.ConsumeBytes<uint8_t>(
+      metadataSize + (srcFrameSize * srcNumFrames));
+  Provider provider(inputData.data(), srcNumFrames, srcFrameSize);
+
+  const uint32_t dstFrameSize = dstChannelCount * audio_bytes_per_sample(dstFormat);
+  const size_t frames = fdp.ConsumeIntegralInRange<size_t>(0, MAX_FRAMES + 1);
+  int8_t dst[dstFrameSize * frames];
+  memset(dst, 0, sizeof(int8_t) * dstFrameSize * frames);
+
+  // Add a small number of loops to see if repeated calls to convert cause
+  // any change in behavior.
+  const int numLoops = fdp.ConsumeIntegralInRange<int>(1, 3);
+  for (int loop = 0; loop < numLoops; ++loop) {
+    switch (fdp.ConsumeIntegralInRange<int>(0, 1)) {
+      case 0:
+        converter.reset();
+        FALLTHROUGH_INTENDED;
+      case 1:
+        converter.convert(dst, &provider, frames);
+        break;
+    }
+  }
+
+  return 0;
+}
diff --git a/media/libaudioprocessing/tests/fuzzer/libaudioprocessing_resampler_fuzzer.cpp b/media/libaudioprocessing/tests/fuzzer/libaudioprocessing_resampler_fuzzer.cpp
index 938c610..65c9a3c 100644
--- a/media/libaudioprocessing/tests/fuzzer/libaudioprocessing_resampler_fuzzer.cpp
+++ b/media/libaudioprocessing/tests/fuzzer/libaudioprocessing_resampler_fuzzer.cpp
@@ -34,6 +34,8 @@
 #include <unistd.h>
 #include <utils/Vector.h>
 
+#include "libaudioprocessing_fuzz_utils.h"
+
 #include <memory>
 
 using namespace android;
@@ -53,46 +55,6 @@
     AudioResampler::DYN_HIGH_QUALITY,
 };
 
-class Provider : public AudioBufferProvider {
-  const void* mAddr;        // base address
-  const size_t mNumFrames;  // total frames
-  const size_t mFrameSize;  // size of each frame in bytes
-  size_t mNextFrame;        // index of next frame to provide
-  size_t mUnrel;            // number of frames not yet released
- public:
-  Provider(const void* addr, size_t frames, size_t frameSize)
-      : mAddr(addr),
-        mNumFrames(frames),
-        mFrameSize(frameSize),
-        mNextFrame(0),
-        mUnrel(0) {}
-  status_t getNextBuffer(Buffer* buffer) override {
-    if (buffer->frameCount > mNumFrames - mNextFrame) {
-      buffer->frameCount = mNumFrames - mNextFrame;
-    }
-    mUnrel = buffer->frameCount;
-    if (buffer->frameCount > 0) {
-      buffer->raw = (char*)mAddr + mFrameSize * mNextFrame;
-      return NO_ERROR;
-    } else {
-      buffer->raw = nullptr;
-      return NOT_ENOUGH_DATA;
-    }
-  }
-  virtual void releaseBuffer(Buffer* buffer) {
-    if (buffer->frameCount > mUnrel) {
-      mNextFrame += mUnrel;
-      mUnrel = 0;
-    } else {
-      mNextFrame += buffer->frameCount;
-      mUnrel -= buffer->frameCount;
-    }
-    buffer->frameCount = 0;
-    buffer->raw = nullptr;
-  }
-  void reset() { mNextFrame = 0; }
-};
-
 audio_format_t chooseFormat(AudioResampler::src_quality quality,
                             uint8_t input_byte) {
   switch (quality) {