You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
300 lines
10 KiB
300 lines
10 KiB
/******************************************************************************
|
|
*
|
|
* 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.
|
|
*
|
|
*****************************************************************************
|
|
* Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore
|
|
*/
|
|
|
|
#include <ServiceLog.h>
|
|
#include <aidl/android/media/BnResourceManagerClient.h>
|
|
#include <media/MediaResource.h>
|
|
#include <media/MediaResourcePolicy.h>
|
|
#include <media/stagefright/ProcessInfoInterface.h>
|
|
#include <media/stagefright/foundation/ADebug.h>
|
|
#include "ResourceManagerService.h"
|
|
#include "fuzzer/FuzzedDataProvider.h"
|
|
|
|
using namespace std;
|
|
using namespace android;
|
|
using Status = ::ndk::ScopedAStatus;
|
|
using ::aidl::android::media::BnResourceManagerClient;
|
|
using ::aidl::android::media::IResourceManagerClient;
|
|
using ::aidl::android::media::IResourceManagerService;
|
|
using MedResType = aidl::android::media::MediaResourceType;
|
|
using MedResSubType = aidl::android::media::MediaResourceSubType;
|
|
|
|
const size_t kMaxStringLength = 100;
|
|
const int32_t kMaxServiceLog = 100;
|
|
const int32_t kMinServiceLog = 1;
|
|
const int32_t kMinResourceType = 0;
|
|
const int32_t kMaxResourceType = 10;
|
|
const int32_t kMinThreadPairs = 1;
|
|
const int32_t kMaxThreadPairs = 3;
|
|
|
|
const string kPolicyType[] = {IResourceManagerService::kPolicySupportsMultipleSecureCodecs,
|
|
IResourceManagerService::kPolicySupportsSecureWithNonSecureCodec};
|
|
|
|
struct resourceThreadArgs {
|
|
int32_t pid;
|
|
int32_t uid;
|
|
int64_t testClientId;
|
|
shared_ptr<ResourceManagerService> service;
|
|
shared_ptr<IResourceManagerClient> testClient;
|
|
vector<MediaResourceParcel> mediaResource;
|
|
};
|
|
|
|
static int64_t getId(const shared_ptr<IResourceManagerClient>& client) {
|
|
return (int64_t)client.get();
|
|
}
|
|
|
|
struct TestProcessInfo : public ProcessInfoInterface {
|
|
TestProcessInfo() {}
|
|
virtual ~TestProcessInfo() {}
|
|
|
|
virtual bool getPriority(int pid, int* priority) {
|
|
// For testing, use pid as priority.
|
|
// Lower the value higher the priority.
|
|
*priority = pid;
|
|
return true;
|
|
}
|
|
|
|
virtual bool isValidPid(int /* pid */) { return true; }
|
|
virtual bool overrideProcessInfo(int /* pid */, int /*procState*/, int /*oomScore*/) {
|
|
return true;
|
|
}
|
|
virtual void removeProcessInfoOverride(int /* pid */) { return; }
|
|
|
|
private:
|
|
DISALLOW_EVIL_CONSTRUCTORS(TestProcessInfo);
|
|
};
|
|
|
|
struct TestSystemCallback : public ResourceManagerService::SystemCallbackInterface {
|
|
TestSystemCallback() : mLastEvent({EventType::INVALID, 0}), mEventCount(0) {}
|
|
|
|
enum EventType {
|
|
INVALID = -1,
|
|
VIDEO_ON = 0,
|
|
VIDEO_OFF = 1,
|
|
VIDEO_RESET = 2,
|
|
CPUSET_ENABLE = 3,
|
|
CPUSET_DISABLE = 4,
|
|
};
|
|
|
|
struct EventEntry {
|
|
EventType type;
|
|
int arg;
|
|
};
|
|
|
|
virtual void noteStartVideo(int uid) override {
|
|
mLastEvent = {EventType::VIDEO_ON, uid};
|
|
++mEventCount;
|
|
}
|
|
|
|
virtual void noteStopVideo(int uid) override {
|
|
mLastEvent = {EventType::VIDEO_OFF, uid};
|
|
++mEventCount;
|
|
}
|
|
|
|
virtual void noteResetVideo() override {
|
|
mLastEvent = {EventType::VIDEO_RESET, 0};
|
|
++mEventCount;
|
|
}
|
|
|
|
virtual bool requestCpusetBoost(bool enable) override {
|
|
mLastEvent = {enable ? EventType::CPUSET_ENABLE : EventType::CPUSET_DISABLE, 0};
|
|
++mEventCount;
|
|
return true;
|
|
}
|
|
|
|
size_t eventCount() { return mEventCount; }
|
|
EventType lastEventType() { return mLastEvent.type; }
|
|
EventEntry lastEvent() { return mLastEvent; }
|
|
|
|
protected:
|
|
virtual ~TestSystemCallback() {}
|
|
|
|
private:
|
|
EventEntry mLastEvent;
|
|
size_t mEventCount;
|
|
|
|
DISALLOW_EVIL_CONSTRUCTORS(TestSystemCallback);
|
|
};
|
|
|
|
struct TestClient : public BnResourceManagerClient {
|
|
TestClient(int pid, const shared_ptr<ResourceManagerService>& service)
|
|
: mReclaimed(false), mPid(pid), mService(service) {}
|
|
|
|
Status reclaimResource(bool* aidlReturn) override {
|
|
mService->removeClient(mPid, getId(ref<TestClient>()));
|
|
mReclaimed = true;
|
|
*aidlReturn = true;
|
|
return Status::ok();
|
|
}
|
|
|
|
Status getName(string* aidlReturn) override {
|
|
*aidlReturn = "test_client";
|
|
return Status::ok();
|
|
}
|
|
|
|
virtual ~TestClient() {}
|
|
|
|
private:
|
|
bool mReclaimed;
|
|
int mPid;
|
|
shared_ptr<ResourceManagerService> mService;
|
|
DISALLOW_EVIL_CONSTRUCTORS(TestClient);
|
|
};
|
|
|
|
class ResourceManagerServiceFuzzer {
|
|
public:
|
|
ResourceManagerServiceFuzzer() = default;
|
|
~ResourceManagerServiceFuzzer() {
|
|
mService = nullptr;
|
|
delete mFuzzedDataProvider;
|
|
}
|
|
void process(const uint8_t* data, size_t size);
|
|
|
|
private:
|
|
void setConfig();
|
|
void setResources();
|
|
void setServiceLog();
|
|
|
|
static void* addResource(void* arg) {
|
|
resourceThreadArgs* tArgs = (resourceThreadArgs*)arg;
|
|
if (tArgs) {
|
|
(tArgs->service)
|
|
->addResource(tArgs->pid, tArgs->uid, tArgs->testClientId, tArgs->testClient,
|
|
tArgs->mediaResource);
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
static void* removeResource(void* arg) {
|
|
resourceThreadArgs* tArgs = (resourceThreadArgs*)arg;
|
|
if (tArgs) {
|
|
bool result;
|
|
(tArgs->service)->markClientForPendingRemoval(tArgs->pid, tArgs->testClientId);
|
|
(tArgs->service)->removeResource(tArgs->pid, tArgs->testClientId, tArgs->mediaResource);
|
|
(tArgs->service)->reclaimResource(tArgs->pid, tArgs->mediaResource, &result);
|
|
(tArgs->service)->removeClient(tArgs->pid, tArgs->testClientId);
|
|
(tArgs->service)->overridePid(tArgs->pid, tArgs->pid - 1);
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
shared_ptr<ResourceManagerService> mService =
|
|
::ndk::SharedRefBase::make<ResourceManagerService>(new TestProcessInfo(),
|
|
new TestSystemCallback());
|
|
FuzzedDataProvider* mFuzzedDataProvider = nullptr;
|
|
};
|
|
|
|
void ResourceManagerServiceFuzzer::process(const uint8_t* data, size_t size) {
|
|
mFuzzedDataProvider = new FuzzedDataProvider(data, size);
|
|
setConfig();
|
|
setResources();
|
|
setServiceLog();
|
|
}
|
|
|
|
void ResourceManagerServiceFuzzer::setConfig() {
|
|
bool policyTypeIndex = mFuzzedDataProvider->ConsumeBool();
|
|
string policyValue = mFuzzedDataProvider->ConsumeRandomLengthString(kMaxStringLength);
|
|
if (mService) {
|
|
vector<MediaResourcePolicyParcel> policies;
|
|
policies.push_back(MediaResourcePolicy(kPolicyType[policyTypeIndex], policyValue));
|
|
mService->config(policies);
|
|
}
|
|
}
|
|
|
|
void ResourceManagerServiceFuzzer::setResources() {
|
|
if (!mService) {
|
|
return;
|
|
}
|
|
size_t numThreadPairs =
|
|
mFuzzedDataProvider->ConsumeIntegralInRange<size_t>(kMinThreadPairs, kMaxThreadPairs);
|
|
// Make even number of threads
|
|
size_t numThreads = numThreadPairs * 2;
|
|
resourceThreadArgs threadArgs;
|
|
vector<MediaResourceParcel> mediaResource;
|
|
pthread_t pt[numThreads];
|
|
int i;
|
|
for (i = 0; i < numThreads - 1; i += 2) {
|
|
threadArgs.pid = mFuzzedDataProvider->ConsumeIntegral<int32_t>();
|
|
threadArgs.uid = mFuzzedDataProvider->ConsumeIntegral<int32_t>();
|
|
int32_t mediaResourceType = mFuzzedDataProvider->ConsumeIntegralInRange<int32_t>(
|
|
kMinResourceType, kMaxResourceType);
|
|
int32_t mediaResourceSubType = mFuzzedDataProvider->ConsumeIntegralInRange<int32_t>(
|
|
kMinResourceType, kMaxResourceType);
|
|
uint64_t mediaResourceValue = mFuzzedDataProvider->ConsumeIntegral<uint64_t>();
|
|
threadArgs.service = mService;
|
|
shared_ptr<IResourceManagerClient> testClient =
|
|
::ndk::SharedRefBase::make<TestClient>(threadArgs.pid, mService);
|
|
threadArgs.testClient = testClient;
|
|
threadArgs.testClientId = getId(testClient);
|
|
mediaResource.push_back(MediaResource(static_cast<MedResType>(mediaResourceType),
|
|
static_cast<MedResSubType>(mediaResourceSubType),
|
|
mediaResourceValue));
|
|
threadArgs.mediaResource = mediaResource;
|
|
pthread_create(&pt[i], nullptr, addResource, &threadArgs);
|
|
pthread_create(&pt[i + 1], nullptr, removeResource, &threadArgs);
|
|
mediaResource.clear();
|
|
}
|
|
|
|
for (i = 0; i < numThreads; ++i) {
|
|
pthread_join(pt[i], nullptr);
|
|
}
|
|
|
|
// No resource was added with pid = 0
|
|
int32_t pidZero = 0;
|
|
shared_ptr<IResourceManagerClient> testClient =
|
|
::ndk::SharedRefBase::make<TestClient>(pidZero, mService);
|
|
int32_t mediaResourceType =
|
|
mFuzzedDataProvider->ConsumeIntegralInRange<int32_t>(kMinResourceType, kMaxResourceType);
|
|
int32_t mediaResourceSubType =
|
|
mFuzzedDataProvider->ConsumeIntegralInRange<int32_t>(kMinResourceType, kMaxResourceType);
|
|
uint64_t mediaResourceValue = mFuzzedDataProvider->ConsumeIntegral<uint64_t>();
|
|
mediaResource.push_back(MediaResource(static_cast<MedResType>(mediaResourceType),
|
|
static_cast<MedResSubType>(mediaResourceSubType),
|
|
mediaResourceValue));
|
|
bool result;
|
|
mService->reclaimResource(pidZero, mediaResource, &result);
|
|
mService->removeResource(pidZero, getId(testClient), mediaResource);
|
|
mService->removeClient(pidZero, getId(testClient));
|
|
mediaResource.clear();
|
|
}
|
|
|
|
void ResourceManagerServiceFuzzer::setServiceLog() {
|
|
size_t maxNum =
|
|
mFuzzedDataProvider->ConsumeIntegralInRange<int32_t>(kMinServiceLog, kMaxServiceLog);
|
|
sp<ServiceLog> serviceLog = new ServiceLog(maxNum);
|
|
if (serviceLog) {
|
|
serviceLog->add(String8("log"));
|
|
serviceLog->toString();
|
|
}
|
|
}
|
|
|
|
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
|
|
if (size < 1) {
|
|
return 0;
|
|
}
|
|
ResourceManagerServiceFuzzer* rmFuzzer = new ResourceManagerServiceFuzzer();
|
|
if (!rmFuzzer) {
|
|
return 0;
|
|
}
|
|
rmFuzzer->process(data, size);
|
|
delete rmFuzzer;
|
|
return 0;
|
|
}
|