Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit af8fd30b authored by Kris Alder's avatar Kris Alder Committed by Android (Google) Code Review
Browse files

Merge "Added mediarecorder_fuzzer"

parents d4b07a04 41da5034
Loading
Loading
Loading
Loading
+65 −0
Original line number Diff line number Diff line
/*
 * 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",
    ],
}
+26 −0
Original line number Diff line number Diff line
# 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
```
+312 −0
Original line number Diff line number Diff line
/*
 * 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;
}