blob: a189d045afccb4e9e33894d5330ddaca3425b67a [file] [log] [blame]
/*
* 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 <MediaPlayerService.h>
#include <camera/Camera.h>
#include <datasource/FileSource.h>
#include <gui/Surface.h>
#include <gui/SurfaceComposerClient.h>
#include <media/IMediaCodecList.h>
#include <media/IMediaHTTPService.h>
#include <media/IMediaPlayer.h>
#include <media/IMediaRecorder.h>
#include <media/IRemoteDisplay.h>
#include <media/IRemoteDisplayClient.h>
#include <media/MediaHTTPConnection.h>
#include <media/MediaHTTPService.h>
#include <media/stagefright/RemoteDataSource.h>
#include <media/stagefright/foundation/base64.h>
#include <thread>
#include "fuzzer/FuzzedDataProvider.h"
constexpr int32_t kUuidSize = 16;
constexpr int32_t kMaxSleepTimeInMs = 100;
constexpr int32_t kMinSleepTimeInMs = 0;
constexpr int32_t kPlayCountMin = 1;
constexpr int32_t kPlayCountMax = 10;
constexpr int32_t kMaxDimension = 8192;
constexpr int32_t kMinDimension = 0;
using namespace std;
using namespace android;
constexpr audio_session_t kSupportedAudioSessions[] = {
AUDIO_SESSION_DEVICE, AUDIO_SESSION_OUTPUT_STAGE, AUDIO_SESSION_OUTPUT_MIX};
constexpr audio_timestretch_stretch_mode_t kAudioStretchModes[] = {
AUDIO_TIMESTRETCH_STRETCH_DEFAULT, AUDIO_TIMESTRETCH_STRETCH_VOICE};
constexpr audio_timestretch_fallback_mode_t kAudioFallbackModes[] = {
AUDIO_TIMESTRETCH_FALLBACK_CUT_REPEAT, AUDIO_TIMESTRETCH_FALLBACK_DEFAULT,
AUDIO_TIMESTRETCH_FALLBACK_MUTE, AUDIO_TIMESTRETCH_FALLBACK_FAIL};
constexpr media_parameter_keys kMediaParamKeys[] = {
KEY_PARAMETER_CACHE_STAT_COLLECT_FREQ_MS, KEY_PARAMETER_AUDIO_CHANNEL_COUNT,
KEY_PARAMETER_PLAYBACK_RATE_PERMILLE, KEY_PARAMETER_AUDIO_ATTRIBUTES,
KEY_PARAMETER_RTP_ATTRIBUTES};
constexpr audio_stream_type_t kAudioStreamTypes[] = {
AUDIO_STREAM_DEFAULT, AUDIO_STREAM_VOICE_CALL, AUDIO_STREAM_SYSTEM,
AUDIO_STREAM_RING, AUDIO_STREAM_MUSIC, AUDIO_STREAM_ALARM,
AUDIO_STREAM_NOTIFICATION, AUDIO_STREAM_BLUETOOTH_SCO, AUDIO_STREAM_ENFORCED_AUDIBLE,
AUDIO_STREAM_DTMF, AUDIO_STREAM_TTS, AUDIO_STREAM_ASSISTANT};
constexpr media_event_type kMediaEventTypes[] = {MEDIA_NOP,
MEDIA_PREPARED,
MEDIA_PLAYBACK_COMPLETE,
MEDIA_BUFFERING_UPDATE,
MEDIA_SEEK_COMPLETE,
MEDIA_SET_VIDEO_SIZE,
MEDIA_STARTED,
MEDIA_PAUSED,
MEDIA_STOPPED,
MEDIA_SKIPPED,
MEDIA_NOTIFY_TIME,
MEDIA_TIMED_TEXT,
MEDIA_ERROR,
MEDIA_INFO,
MEDIA_SUBTITLE_DATA,
MEDIA_META_DATA,
MEDIA_DRM_INFO,
MEDIA_TIME_DISCONTINUITY,
MEDIA_IMS_RX_NOTICE,
MEDIA_AUDIO_ROUTING_CHANGED};
constexpr media_info_type kMediaInfoTypes[] = {
MEDIA_INFO_UNKNOWN, MEDIA_INFO_STARTED_AS_NEXT,
MEDIA_INFO_RENDERING_START, MEDIA_INFO_VIDEO_TRACK_LAGGING,
MEDIA_INFO_BUFFERING_START, MEDIA_INFO_BUFFERING_END,
MEDIA_INFO_NETWORK_BANDWIDTH, MEDIA_INFO_BAD_INTERLEAVING,
MEDIA_INFO_NOT_SEEKABLE, MEDIA_INFO_METADATA_UPDATE,
MEDIA_INFO_PLAY_AUDIO_ERROR, MEDIA_INFO_PLAY_VIDEO_ERROR,
MEDIA_INFO_TIMED_TEXT_ERROR};
const char *kUrlPrefix[] = {"data:", "http://", "https://", "rtsp://", "content://", "test://"};
struct TestStreamSource : public IStreamSource {
void setListener(const sp<IStreamListener> & /*listener*/) override{};
void setBuffers(const Vector<sp<IMemory>> & /*buffers*/) override{};
void onBufferAvailable(size_t /*index*/) override{};
IBinder *onAsBinder() { return nullptr; };
};
struct TestMediaHTTPConnection : public MediaHTTPConnection {
public:
TestMediaHTTPConnection() {}
virtual ~TestMediaHTTPConnection() {}
virtual bool connect(const char* /*uri*/, const KeyedVector<String8, String8>* /*headers*/) {
return true;
}
virtual void disconnect() { return; }
virtual ssize_t readAt(off64_t /*offset*/, void* /*data*/, size_t size) { return size; }
virtual off64_t getSize() { return 0; }
virtual status_t getMIMEType(String8* /*mimeType*/) { return NO_ERROR; }
virtual status_t getUri(String8* /*uri*/) { return NO_ERROR; }
private:
DISALLOW_EVIL_CONSTRUCTORS(TestMediaHTTPConnection);
};
struct TestMediaHTTPService : public BnInterface<IMediaHTTPService> {
public:
TestMediaHTTPService() {}
~TestMediaHTTPService(){};
virtual sp<MediaHTTPConnection> makeHTTPConnection() {
mMediaHTTPConnection = sp<TestMediaHTTPConnection>::make();
return mMediaHTTPConnection;
}
private:
sp<TestMediaHTTPConnection> mMediaHTTPConnection = nullptr;
DISALLOW_EVIL_CONSTRUCTORS(TestMediaHTTPService);
};
class BinderDeathNotifier : public IBinder::DeathRecipient {
public:
void binderDied(const wp<IBinder> &) { abort(); }
};
class MediaPlayerServiceFuzzer {
public:
MediaPlayerServiceFuzzer(const uint8_t *data, size_t size)
: mFdp(data, size), mDataSourceFd(memfd_create("InputFile", MFD_ALLOW_SEALING)){};
~MediaPlayerServiceFuzzer() { close(mDataSourceFd); };
void process(const uint8_t *data, size_t size);
private:
bool setDataSource(const uint8_t *data, size_t size);
void invokeMediaPlayer();
FuzzedDataProvider mFdp;
sp<IMediaPlayer> mMediaPlayer = nullptr;
sp<IMediaPlayerClient> mMediaPlayerClient = nullptr;
const int32_t mDataSourceFd;
};
bool MediaPlayerServiceFuzzer::setDataSource(const uint8_t *data, size_t size) {
status_t status = -1;
enum DataSourceType {http, fd, stream, file, socket, kMaxValue = socket};
switch (mFdp.ConsumeEnum<DataSourceType>()) {
case http: {
KeyedVector<String8, String8> headers;
headers.add(String8(mFdp.ConsumeRandomLengthString().c_str()),
String8(mFdp.ConsumeRandomLengthString().c_str()));
uint32_t dataBlobSize = mFdp.ConsumeIntegralInRange<uint16_t>(0, size);
vector<uint8_t> uriSuffix = mFdp.ConsumeBytes<uint8_t>(dataBlobSize);
string uri(mFdp.PickValueInArray(kUrlPrefix));
uri += ";base64,";
AString out;
encodeBase64(uriSuffix.data(), uriSuffix.size(), &out);
uri += out.c_str();
sp<TestMediaHTTPService> testService = sp<TestMediaHTTPService>::make();
status =
mMediaPlayer->setDataSource(testService /*httpService*/, uri.c_str(), &headers);
break;
}
case fd: {
write(mDataSourceFd, data, size);
status = mMediaPlayer->setDataSource(mDataSourceFd, 0, size);
break;
}
case stream: {
sp<IStreamSource> streamSource = sp<TestStreamSource>::make();
status = mMediaPlayer->setDataSource(streamSource);
break;
}
case file: {
write(mDataSourceFd, data, size);
sp<DataSource> dataSource = new FileSource(dup(mDataSourceFd), 0, size);
sp<IDataSource> iDataSource = RemoteDataSource::wrap(dataSource);
if (!iDataSource) {
return false;
}
status = mMediaPlayer->setDataSource(iDataSource);
break;
}
case socket: {
String8 rtpParams = String8(mFdp.ConsumeRandomLengthString().c_str());
struct sockaddr_in endpoint;
endpoint.sin_family = mFdp.ConsumeIntegral<unsigned short>();
endpoint.sin_port = mFdp.ConsumeIntegral<uint16_t>();
mMediaPlayer->setRetransmitEndpoint(&endpoint);
status = mMediaPlayer->setDataSource(rtpParams);
break;
}
}
if (status != 0) {
return false;
}
return true;
}
void MediaPlayerServiceFuzzer::invokeMediaPlayer() {
sp<SurfaceComposerClient> composerClient = new SurfaceComposerClient;
String8 name = String8(mFdp.ConsumeRandomLengthString().c_str());
uint32_t width = mFdp.ConsumeIntegralInRange<uint32_t>(kMinDimension, kMaxDimension);
uint32_t height = mFdp.ConsumeIntegralInRange<uint32_t>(kMinDimension, kMaxDimension);
uint32_t pixelFormat = mFdp.ConsumeIntegral<int32_t>();
uint32_t flags = mFdp.ConsumeIntegral<int32_t>();
sp<SurfaceControl> surfaceControl =
composerClient->createSurface(name, width, height, pixelFormat, flags);
if (surfaceControl) {
sp<Surface> surface = surfaceControl->getSurface();
mMediaPlayer->setVideoSurfaceTexture(surface->getIGraphicBufferProducer());
}
BufferingSettings buffering;
buffering.mInitialMarkMs = mFdp.ConsumeIntegral<int32_t>();
buffering.mResumePlaybackMarkMs = mFdp.ConsumeIntegral<int32_t>();
mMediaPlayer->setBufferingSettings(buffering);
mMediaPlayer->getBufferingSettings(&buffering);
mMediaPlayer->prepareAsync();
size_t playCount = mFdp.ConsumeIntegralInRange<size_t>(kPlayCountMin, kPlayCountMax);
for (size_t Idx = 0; Idx < playCount; ++Idx) {
mMediaPlayer->start();
this_thread::sleep_for(chrono::milliseconds(
mFdp.ConsumeIntegralInRange<int32_t>(kMinSleepTimeInMs, kMaxSleepTimeInMs)));
mMediaPlayer->pause();
this_thread::sleep_for(chrono::milliseconds(
mFdp.ConsumeIntegralInRange<int32_t>(kMinSleepTimeInMs, kMaxSleepTimeInMs)));
mMediaPlayer->stop();
}
bool state;
mMediaPlayer->isPlaying(&state);
AudioPlaybackRate rate;
rate.mSpeed = mFdp.ConsumeFloatingPoint<float>();
rate.mPitch = mFdp.ConsumeFloatingPoint<float>();
rate.mStretchMode = mFdp.PickValueInArray(kAudioStretchModes);
rate.mFallbackMode = mFdp.PickValueInArray(kAudioFallbackModes);
mMediaPlayer->setPlaybackSettings(rate);
mMediaPlayer->getPlaybackSettings(&rate);
AVSyncSettings *avSyncSettings = new AVSyncSettings();
float videoFpsHint = mFdp.ConsumeFloatingPoint<float>();
mMediaPlayer->setSyncSettings(*avSyncSettings, videoFpsHint);
mMediaPlayer->getSyncSettings(avSyncSettings, &videoFpsHint);
delete avSyncSettings;
mMediaPlayer->seekTo(mFdp.ConsumeIntegral<int32_t>());
int32_t msec;
mMediaPlayer->getCurrentPosition(&msec);
mMediaPlayer->getDuration(&msec);
mMediaPlayer->reset();
mMediaPlayer->notifyAt(mFdp.ConsumeIntegral<int64_t>());
mMediaPlayer->setAudioStreamType(mFdp.PickValueInArray(kAudioStreamTypes));
mMediaPlayer->setLooping(mFdp.ConsumeIntegral<int32_t>());
float left = mFdp.ConsumeFloatingPoint<float>();
float right = mFdp.ConsumeFloatingPoint<float>();
mMediaPlayer->setVolume(left, right);
Parcel request, reply;
request.writeInt32(mFdp.ConsumeIntegral<int32_t>());
request.setDataPosition(0);
mMediaPlayer->invoke(request, &reply);
Parcel filter;
filter.writeInt32(mFdp.ConsumeIntegral<int32_t>());
filter.setDataPosition(0);
mMediaPlayer->setMetadataFilter(filter);
bool updateOnly = mFdp.ConsumeBool();
bool applyFilter = mFdp.ConsumeBool();
mMediaPlayer->getMetadata(updateOnly, applyFilter, &reply);
mMediaPlayer->setAuxEffectSendLevel(mFdp.ConsumeFloatingPoint<float>());
mMediaPlayer->attachAuxEffect(mFdp.ConsumeIntegral<int32_t>());
int32_t key = mFdp.PickValueInArray(kMediaParamKeys);
request.writeInt32(mFdp.ConsumeIntegral<int32_t>());
request.setDataPosition(0);
mMediaPlayer->setParameter(key, request);
key = mFdp.PickValueInArray(kMediaParamKeys);
mMediaPlayer->getParameter(key, &reply);
struct sockaddr_in endpoint;
mMediaPlayer->getRetransmitEndpoint(&endpoint);
AttributionSourceState attributionSource;
attributionSource.packageName = mFdp.ConsumeRandomLengthString().c_str();
attributionSource.token = sp<BBinder>::make();
const sp<IMediaPlayerService> mpService(IMediaDeathNotifier::getMediaPlayerService());
sp<IMediaPlayer> mNextMediaPlayer = mpService->create(
mMediaPlayerClient, mFdp.PickValueInArray(kSupportedAudioSessions), attributionSource);
mMediaPlayer->setNextPlayer(mNextMediaPlayer);
const sp<media::VolumeShaper::Configuration> configuration =
sp<media::VolumeShaper::Configuration>::make();
const sp<media::VolumeShaper::Operation> operation = sp<media::VolumeShaper::Operation>::make();
mMediaPlayer->applyVolumeShaper(configuration, operation);
mMediaPlayer->getVolumeShaperState(mFdp.ConsumeIntegral<int32_t>());
uint8_t uuid[kUuidSize];
for (int32_t index = 0; index < kUuidSize; ++index) {
uuid[index] = mFdp.ConsumeIntegral<uint8_t>();
}
Vector<uint8_t> drmSessionId;
drmSessionId.push_back(mFdp.ConsumeIntegral<uint8_t>());
mMediaPlayer->prepareDrm(uuid, drmSessionId);
mMediaPlayer->releaseDrm();
audio_port_handle_t deviceId = mFdp.ConsumeIntegral<int32_t>();
mMediaPlayer->setOutputDevice(deviceId);
mMediaPlayer->getRoutedDeviceId(&deviceId);
mMediaPlayer->enableAudioDeviceCallback(mFdp.ConsumeBool());
sp<MediaPlayer> mediaPlayer = (MediaPlayer *)mMediaPlayer.get();
int32_t msg = mFdp.PickValueInArray(kMediaEventTypes);
int32_t ext1 = mFdp.PickValueInArray(kMediaInfoTypes);
int32_t ext2 = mFdp.ConsumeIntegral<int32_t>();
Parcel obj;
obj.writeInt32(mFdp.ConsumeIntegral<int32_t>());
obj.setDataPosition(0);
mediaPlayer->notify(msg, ext1, ext2, &obj);
int32_t mediaPlayerDumpFd = memfd_create("OutputDumpFile", MFD_ALLOW_SEALING);
Vector<String16> args;
args.push_back(String16(mFdp.ConsumeRandomLengthString().c_str()));
mediaPlayer->dump(mediaPlayerDumpFd, args);
close(mediaPlayerDumpFd);
mMediaPlayer->disconnect();
}
void MediaPlayerServiceFuzzer::process(const uint8_t *data, size_t size) {
MediaPlayerService::instantiate();
const sp<IMediaPlayerService> mpService(IMediaDeathNotifier::getMediaPlayerService());
if (!mpService) {
return;
}
sp<IMediaCodecList> mediaCodecList = mpService->getCodecList();
sp<IRemoteDisplayClient> remoteDisplayClient;
sp<IRemoteDisplay> remoteDisplay = mpService->listenForRemoteDisplay(
String16(mFdp.ConsumeRandomLengthString().c_str()) /*opPackageName*/, remoteDisplayClient,
String8(mFdp.ConsumeRandomLengthString().c_str()) /*iface*/);
mpService->addBatteryData(mFdp.ConsumeIntegral<uint32_t>());
Parcel reply;
mpService->pullBatteryData(&reply);
sp<MediaPlayerService> mediaPlayerService = (MediaPlayerService *)mpService.get();
AttributionSourceState attributionSource;
attributionSource.packageName = mFdp.ConsumeRandomLengthString().c_str();
attributionSource.token = sp<BBinder>::make();
mMediaPlayer = mediaPlayerService->create(
mMediaPlayerClient, mFdp.PickValueInArray(kSupportedAudioSessions), attributionSource);
int32_t mediaPlayerServiceDumpFd = memfd_create("OutputDumpFile", MFD_ALLOW_SEALING);
Vector<String16> args;
args.push_back(String16(mFdp.ConsumeRandomLengthString().c_str()));
mediaPlayerService->dump(mediaPlayerServiceDumpFd, args);
close(mediaPlayerServiceDumpFd);
if (!mMediaPlayer) {
return;
}
if (setDataSource(data, size)) {
invokeMediaPlayer();
}
}
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
MediaPlayerServiceFuzzer mpsFuzzer(data, size);
ProcessState::self()->startThreadPool();
mpsFuzzer.process(data, size);
return 0;
};