Merge "Added mediarecorder_fuzzer"
diff --git a/media/libmediaplayerservice/fuzzer/Android.bp b/media/libmediaplayerservice/fuzzer/Android.bp
new file mode 100644
index 0000000..fb1d494
--- /dev/null
+++ b/media/libmediaplayerservice/fuzzer/Android.bp
@@ -0,0 +1,65 @@
+/*
+ * 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.
+ *
+ */
+
+cc_defaults {
+ name: "libmediaplayerserviceFuzzer_defaults",
+ include_dirs: [
+ "frameworks/av/media/libmediaplayerservice",
+ ],
+ static_libs: [
+ "libmediaplayerservice",
+ "liblog",
+ ],
+ shared_libs: [
+ "framework-permission-aidl-cpp",
+ "libbinder",
+ "libcutils",
+ "libmedia",
+ "libstagefright",
+ "libutils",
+ "libstagefright_foundation",
+ ],
+ fuzz_config: {
+ cc: [
+ "android-media-fuzzing-reports@google.com",
+ ],
+ componentid: 155276,
+ },
+}
+
+cc_fuzz {
+ name: "mediarecorder_fuzzer",
+ srcs: [
+ "mediarecorder_fuzzer.cpp",
+ ],
+ defaults: [
+ "libmediaplayerserviceFuzzer_defaults",
+ ],
+ static_libs: [
+ "libstagefright_rtsp",
+ "libbase",
+ ],
+ shared_libs: [
+ "av-types-aidl-cpp",
+ "media_permission-aidl-cpp",
+ "libaudioclient_aidl_conversion",
+ "libandroid_net",
+ "libcamera_client",
+ "libgui",
+ "libmediametrics",
+ ],
+}
diff --git a/media/libmediaplayerservice/fuzzer/README.md b/media/libmediaplayerservice/fuzzer/README.md
new file mode 100644
index 0000000..9100f12
--- /dev/null
+++ b/media/libmediaplayerservice/fuzzer/README.md
@@ -0,0 +1,26 @@
+# Fuzzer for libmediaplayerservice
+## Table of contents
++ [StagefrightMediaRecorder](#StagefrightMediaRecorder)
+
+# <a name="StagefrightMediaRecorder"></a> Fuzzer for StagefrightMediaRecorder
+
+StagefrightMediaRecorder supports the following parameters:
+1. Output Formats (parameter name: `setOutputFormat`)
+2. Audio Encoders (parameter name: `setAudioEncoder`)
+3. Video Encoders (parameter name: `setVideoEncoder`)
+4. Audio Sources (parameter name: `setAudioSource`)
+5. Video Sources (parameter name: `setVideoSource`)
+6. Microphone Direction (parameter name: `setMicrophoneDirection`)
+
+You can find the possible values in the fuzzer's source code.
+
+#### Steps to run
+1. Build the fuzzer
+```
+ $ mm -j$(nproc) mediarecorder_fuzzer
+```
+2. Run on device
+```
+ $ adb sync data
+ $ adb shell /data/fuzz/arm64/mediarecorder_fuzzer/mediarecorder_fuzzer
+```
diff --git a/media/libmediaplayerservice/fuzzer/mediarecorder_fuzzer.cpp b/media/libmediaplayerservice/fuzzer/mediarecorder_fuzzer.cpp
new file mode 100644
index 0000000..b0040fe
--- /dev/null
+++ b/media/libmediaplayerservice/fuzzer/mediarecorder_fuzzer.cpp
@@ -0,0 +1,312 @@
+/*
+ * 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.
+ *
+ */
+
+#include <media/stagefright/foundation/AString.h>
+#include "fuzzer/FuzzedDataProvider.h"
+
+#include <StagefrightRecorder.h>
+#include <camera/Camera.h>
+#include <camera/android/hardware/ICamera.h>
+#include <gui/IGraphicBufferProducer.h>
+#include <gui/Surface.h>
+#include <gui/SurfaceComposerClient.h>
+#include <media/stagefright/PersistentSurface.h>
+#include <thread>
+
+using namespace std;
+using namespace android;
+using namespace android::hardware;
+
+constexpr video_source kSupportedVideoSources[] = {VIDEO_SOURCE_DEFAULT, VIDEO_SOURCE_CAMERA,
+ VIDEO_SOURCE_SURFACE};
+
+constexpr audio_source_t kSupportedAudioSources[] = {
+ AUDIO_SOURCE_DEFAULT, AUDIO_SOURCE_MIC,
+ AUDIO_SOURCE_VOICE_UPLINK, AUDIO_SOURCE_VOICE_DOWNLINK,
+ AUDIO_SOURCE_VOICE_CALL, AUDIO_SOURCE_CAMCORDER,
+ AUDIO_SOURCE_VOICE_RECOGNITION, AUDIO_SOURCE_VOICE_COMMUNICATION,
+ AUDIO_SOURCE_REMOTE_SUBMIX, AUDIO_SOURCE_UNPROCESSED,
+ AUDIO_SOURCE_VOICE_PERFORMANCE, AUDIO_SOURCE_ECHO_REFERENCE,
+ AUDIO_SOURCE_FM_TUNER, AUDIO_SOURCE_HOTWORD};
+
+constexpr audio_microphone_direction_t kSupportedMicrophoneDirections[] = {
+ MIC_DIRECTION_UNSPECIFIED, MIC_DIRECTION_FRONT, MIC_DIRECTION_BACK, MIC_DIRECTION_EXTERNAL};
+
+struct RecordingConfig {
+ output_format outputFormat;
+ audio_encoder audioEncoder;
+ video_encoder videoEncoder;
+};
+
+const struct RecordingConfig kRecordingConfigList[] = {
+ {OUTPUT_FORMAT_AMR_NB, AUDIO_ENCODER_AMR_NB, VIDEO_ENCODER_DEFAULT},
+ {OUTPUT_FORMAT_AMR_WB, AUDIO_ENCODER_AMR_WB, VIDEO_ENCODER_DEFAULT},
+ {OUTPUT_FORMAT_AAC_ADTS, AUDIO_ENCODER_AAC, VIDEO_ENCODER_DEFAULT},
+ {OUTPUT_FORMAT_AAC_ADTS, AUDIO_ENCODER_HE_AAC, VIDEO_ENCODER_DEFAULT},
+ {OUTPUT_FORMAT_AAC_ADTS, AUDIO_ENCODER_AAC_ELD, VIDEO_ENCODER_DEFAULT},
+ {OUTPUT_FORMAT_OGG, AUDIO_ENCODER_OPUS, VIDEO_ENCODER_DEFAULT},
+ {OUTPUT_FORMAT_RTP_AVP, AUDIO_ENCODER_DEFAULT, VIDEO_ENCODER_DEFAULT},
+ {OUTPUT_FORMAT_MPEG2TS, AUDIO_ENCODER_AAC, VIDEO_ENCODER_H264},
+ {OUTPUT_FORMAT_WEBM, AUDIO_ENCODER_VORBIS, VIDEO_ENCODER_VP8},
+ {OUTPUT_FORMAT_THREE_GPP, AUDIO_ENCODER_DEFAULT, VIDEO_ENCODER_MPEG_4_SP},
+ {OUTPUT_FORMAT_MPEG_4, AUDIO_ENCODER_AAC, VIDEO_ENCODER_H264},
+ {OUTPUT_FORMAT_MPEG_4, AUDIO_ENCODER_DEFAULT, VIDEO_ENCODER_MPEG_4_SP},
+ {OUTPUT_FORMAT_MPEG_4, AUDIO_ENCODER_DEFAULT, VIDEO_ENCODER_HEVC}};
+
+const string kParametersList[] = {"max-duration",
+ "max-filesize",
+ "interleave-duration-us",
+ "param-movie-time-scale",
+ "param-geotag-longitude",
+ "param-geotag-latitude",
+ "param-track-time-status",
+ "audio-param-sampling-rate",
+ "audio-param-encoding-bitrate",
+ "audio-param-number-of-channels",
+ "audio-param-time-scale",
+ "video-param-rotation-angle-degrees",
+ "video-param-encoding-bitrate",
+ "video-param-bitrate-mode",
+ "video-param-i-frames-interval",
+ "video-param-encoder-profile",
+ "video-param-encoder-level",
+ "video-param-camera-id",
+ "video-param-time-scale",
+ "param-use-64bit-offset",
+ "time-lapse-enable",
+ "time-lapse-fps",
+ "rtp-param-local-ip",
+ "rtp-param-local-port",
+ "rtp-param-remote-port",
+ "rtp-param-self-id",
+ "rtp-param-opponent-id",
+ "rtp-param-payload-type",
+ "rtp-param-ext-cvo-extmap",
+ "rtp-param-ext-cvo-degrees",
+ "video-param-request-i-frame",
+ "rtp-param-set-socket-dscp",
+ "rtp-param-set-socket-network"};
+
+constexpr int32_t kMaxSleepTimeInMs = 100;
+constexpr int32_t kMinSleepTimeInMs = 0;
+constexpr int32_t kMinVideoSize = 2;
+constexpr int32_t kMaxVideoSize = 8192;
+constexpr int32_t kNumRecordMin = 1;
+constexpr int32_t kNumRecordMax = 10;
+
+class TestAudioDeviceCallback : public AudioSystem::AudioDeviceCallback {
+ public:
+ virtual ~TestAudioDeviceCallback() = default;
+
+ void onAudioDeviceUpdate(audio_io_handle_t /*audioIo*/,
+ audio_port_handle_t /*deviceId*/) override{};
+};
+
+class TestCamera : public ICamera {
+ public:
+ virtual ~TestCamera() = default;
+
+ binder::Status disconnect() override { return binder::Status::ok(); };
+ status_t connect(const sp<ICameraClient> & /*client*/) override { return 0; };
+ status_t lock() override { return 0; };
+ status_t unlock() override { return 0; };
+ status_t setPreviewTarget(const sp<IGraphicBufferProducer> & /*bufferProducer*/) override {
+ return 0;
+ };
+ void setPreviewCallbackFlag(int /*flag*/) override{};
+ status_t setPreviewCallbackTarget(
+ const sp<IGraphicBufferProducer> & /*callbackProducer*/) override {
+ return 0;
+ };
+ status_t startPreview() override { return 0; };
+ void stopPreview() override{};
+ bool previewEnabled() override { return true; };
+ status_t startRecording() override { return 0; };
+ void stopRecording() override{};
+ bool recordingEnabled() override { return true; };
+ void releaseRecordingFrame(const sp<IMemory> & /*mem*/) override{};
+ void releaseRecordingFrameHandle(native_handle_t * /*handle*/) override{};
+ void releaseRecordingFrameHandleBatch(const vector<native_handle_t *> & /*handles*/) override{};
+ status_t autoFocus() override { return 0; };
+ status_t cancelAutoFocus() override { return 0; };
+ status_t takePicture(int /*msgType*/) override { return 0; };
+ status_t setParameters(const String8 & /*params*/) override { return 0; };
+ String8 getParameters() const override { return String8(); };
+ status_t sendCommand(int32_t /*cmd*/, int32_t /*arg1*/, int32_t /*arg2*/) override {
+ return 0;
+ };
+ status_t setVideoBufferMode(int32_t /*videoBufferMode*/) override { return 0; };
+ status_t setVideoTarget(const sp<IGraphicBufferProducer> & /*bufferProducer*/) override {
+ return 0;
+ };
+ status_t setAudioRestriction(int32_t /*mode*/) override { return 0; };
+ int32_t getGlobalAudioRestriction() override { return 0; };
+ IBinder *onAsBinder() override { return reinterpret_cast<IBinder *>(this); };
+};
+
+class TestMediaRecorderClient : public IMediaRecorderClient {
+ public:
+ virtual ~TestMediaRecorderClient() = default;
+
+ void notify(int /*msg*/, int /*ext1*/, int /*ext2*/) override{};
+ IBinder *onAsBinder() override { return reinterpret_cast<IBinder *>(this); };
+};
+
+class MediaRecorderClientFuzzer {
+ public:
+ MediaRecorderClientFuzzer(const uint8_t *data, size_t size);
+ ~MediaRecorderClientFuzzer() { close(mMediaRecorderOutputFd); }
+ void process();
+
+ private:
+ void setConfig();
+ void getConfig();
+ void dumpInfo();
+
+ FuzzedDataProvider mFdp;
+ unique_ptr<MediaRecorderBase> mStfRecorder = nullptr;
+ SurfaceComposerClient mComposerClient;
+ sp<SurfaceControl> mSurfaceControl = nullptr;
+ sp<Surface> mSurface = nullptr;
+ const int32_t mMediaRecorderOutputFd;
+};
+
+void MediaRecorderClientFuzzer::getConfig() {
+ int32_t max;
+ mStfRecorder->getMaxAmplitude(&max);
+
+ int32_t deviceId = mFdp.ConsumeIntegral<int32_t>();
+ mStfRecorder->setInputDevice(deviceId);
+ mStfRecorder->getRoutedDeviceId(&deviceId);
+
+ vector<android::media::MicrophoneInfo> activeMicrophones{};
+ mStfRecorder->getActiveMicrophones(&activeMicrophones);
+
+ int32_t portId;
+ mStfRecorder->getPortId(&portId);
+
+ uint64_t bytes;
+ mStfRecorder->getRtpDataUsage(&bytes);
+
+ Parcel parcel;
+ mStfRecorder->getMetrics(&parcel);
+
+ sp<IGraphicBufferProducer> buffer = mStfRecorder->querySurfaceMediaSource();
+}
+
+void MediaRecorderClientFuzzer::dumpInfo() {
+ int32_t dumpFd = memfd_create("DumpFile", MFD_ALLOW_SEALING);
+ Vector<String16> args;
+ args.push_back(String16(mFdp.ConsumeRandomLengthString().c_str()));
+ mStfRecorder->dump(dumpFd, args);
+ close(dumpFd);
+}
+
+void MediaRecorderClientFuzzer::setConfig() {
+ mStfRecorder->setOutputFile(mMediaRecorderOutputFd);
+ mStfRecorder->setAudioSource(mFdp.PickValueInArray(kSupportedAudioSources));
+ mStfRecorder->setVideoSource(mFdp.PickValueInArray(kSupportedVideoSources));
+ mStfRecorder->setPreferredMicrophoneDirection(
+ mFdp.PickValueInArray(kSupportedMicrophoneDirections));
+ mStfRecorder->setPrivacySensitive(mFdp.ConsumeBool());
+ bool isPrivacySensitive;
+ mStfRecorder->isPrivacySensitive(&isPrivacySensitive);
+ mStfRecorder->setVideoSize(mFdp.ConsumeIntegralInRange<int32_t>(kMinVideoSize, kMaxVideoSize),
+ mFdp.ConsumeIntegralInRange<int32_t>(kMinVideoSize, kMaxVideoSize));
+ mStfRecorder->setVideoFrameRate(mFdp.ConsumeIntegral<int32_t>());
+ mStfRecorder->enableAudioDeviceCallback(mFdp.ConsumeBool());
+ mStfRecorder->setPreferredMicrophoneFieldDimension(mFdp.ConsumeFloatingPoint<float>());
+ mStfRecorder->setClientName(String16(mFdp.ConsumeRandomLengthString().c_str()));
+
+ int32_t Idx = mFdp.ConsumeIntegralInRange<int32_t>(0, size(kRecordingConfigList) - 1);
+ mStfRecorder->setOutputFormat(kRecordingConfigList[Idx].outputFormat);
+ mStfRecorder->setAudioEncoder(kRecordingConfigList[Idx].audioEncoder);
+ mStfRecorder->setVideoEncoder(kRecordingConfigList[Idx].videoEncoder);
+
+ int32_t nextOutputFd = memfd_create("NextOutputFile", MFD_ALLOW_SEALING);
+ mStfRecorder->setNextOutputFile(nextOutputFd);
+ close(nextOutputFd);
+
+ for (Idx = 0; Idx < size(kParametersList); ++Idx) {
+ if (mFdp.ConsumeBool()) {
+ int32_t value = mFdp.ConsumeIntegral<int32_t>();
+ mStfRecorder->setParameters(
+ String8((kParametersList[Idx] + "=" + to_string(value)).c_str()));
+ }
+ }
+}
+
+MediaRecorderClientFuzzer::MediaRecorderClientFuzzer(const uint8_t *data, size_t size)
+ : mFdp(data, size), mMediaRecorderOutputFd(memfd_create("OutputFile", MFD_ALLOW_SEALING)) {
+ AttributionSourceState attributionSource;
+ attributionSource.packageName = mFdp.ConsumeRandomLengthString().c_str();
+ attributionSource.token = sp<BBinder>::make();
+ mStfRecorder = make_unique<StagefrightRecorder>(attributionSource);
+
+ mSurfaceControl = mComposerClient.createSurface(
+ String8(mFdp.ConsumeRandomLengthString().c_str()), mFdp.ConsumeIntegral<uint32_t>(),
+ mFdp.ConsumeIntegral<uint32_t>(), mFdp.ConsumeIntegral<int32_t>(),
+ mFdp.ConsumeIntegral<int32_t>());
+ if (mSurfaceControl) {
+ mSurface = mSurfaceControl->getSurface();
+ mStfRecorder->setPreviewSurface(mSurface->getIGraphicBufferProducer());
+ }
+
+ sp<TestMediaRecorderClient> listener = sp<TestMediaRecorderClient>::make();
+ mStfRecorder->setListener(listener);
+
+ sp<TestCamera> testCamera = sp<TestCamera>::make();
+ sp<Camera> camera = Camera::create(testCamera);
+ mStfRecorder->setCamera(camera->remote(), camera->getRecordingProxy());
+
+ sp<PersistentSurface> persistentSurface = sp<PersistentSurface>::make();
+ mStfRecorder->setInputSurface(persistentSurface);
+
+ sp<TestAudioDeviceCallback> callback = sp<TestAudioDeviceCallback>::make();
+ mStfRecorder->setAudioDeviceCallback(callback);
+}
+
+void MediaRecorderClientFuzzer::process() {
+ setConfig();
+
+ mStfRecorder->init();
+ mStfRecorder->prepare();
+ size_t numRecord = mFdp.ConsumeIntegralInRange<size_t>(kNumRecordMin, kNumRecordMax);
+ for (size_t Idx = 0; Idx < numRecord; ++Idx) {
+ mStfRecorder->start();
+ this_thread::sleep_for(chrono::milliseconds(
+ mFdp.ConsumeIntegralInRange<int32_t>(kMinSleepTimeInMs, kMaxSleepTimeInMs)));
+ mStfRecorder->pause();
+ this_thread::sleep_for(chrono::milliseconds(
+ mFdp.ConsumeIntegralInRange<int32_t>(kMinSleepTimeInMs, kMaxSleepTimeInMs)));
+ mStfRecorder->resume();
+ this_thread::sleep_for(chrono::milliseconds(
+ mFdp.ConsumeIntegralInRange<int32_t>(kMinSleepTimeInMs, kMaxSleepTimeInMs)));
+ mStfRecorder->stop();
+ }
+ dumpInfo();
+ getConfig();
+
+ mStfRecorder->close();
+ mStfRecorder->reset();
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+ MediaRecorderClientFuzzer mrcFuzzer(data, size);
+ mrcFuzzer.process();
+ return 0;
+}