Added surfaceflinger_scheduler_fuzzer

Test: ./surfaceflinger_scheduler_fuzzer
Bug: 189053744

Change-Id: I43ec5a97b5d3230c0950f0d9999aa1eef457c126
diff --git a/services/surfaceflinger/fuzzer/Android.bp b/services/surfaceflinger/fuzzer/Android.bp
index 0ead163..b0d216e 100644
--- a/services/surfaceflinger/fuzzer/Android.bp
+++ b/services/surfaceflinger/fuzzer/Android.bp
@@ -92,3 +92,13 @@
         "android.hardware.graphics.composer@2.4-hal",
     ],
 }
+
+cc_fuzz {
+    name: "surfaceflinger_scheduler_fuzzer",
+    defaults: [
+        "surfaceflinger_fuzz_defaults",
+    ],
+    srcs: [
+        "surfaceflinger_scheduler_fuzzer.cpp",
+    ],
+}
diff --git a/services/surfaceflinger/fuzzer/README.md b/services/surfaceflinger/fuzzer/README.md
index 4ecf770..6231ca5 100644
--- a/services/surfaceflinger/fuzzer/README.md
+++ b/services/surfaceflinger/fuzzer/README.md
@@ -2,6 +2,7 @@
 ## Table of contents
 + [SurfaceFlinger](#SurfaceFlinger)
 + [DisplayHardware](#DisplayHardware)
++ [Scheduler](#Scheduler)
 
 # <a name="SurfaceFlinger"></a> Fuzzer for SurfaceFlinger
 
@@ -51,3 +52,21 @@
   $ adb sync data
   $ adb shell /data/fuzz/arm64/surfaceflinger_displayhardware_fuzzer/surfaceflinger_displayhardware_fuzzer
 ```
+
+# <a name="Scheduler"></a> Fuzzer for Scheduler
+
+Scheduler supports the following parameters:
+1. VSync Periods (parameter name: `lowFpsPeriod`)
+
+You can find the possible values in the fuzzer's source code.
+
+#### Steps to run
+1. Build the fuzzer
+```
+  $ mm -j$(nproc) surfaceflinger_scheduler_fuzzer
+```
+2. To run on device
+```
+  $ adb sync data
+  $ adb shell /data/fuzz/arm64/surfaceflinger_scheduler_fuzzer/surfaceflinger_scheduler_fuzzer
+```
diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp b/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp
new file mode 100644
index 0000000..51a5081
--- /dev/null
+++ b/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp
@@ -0,0 +1,392 @@
+/*
+ * Copyright 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 "surfaceflinger_scheduler_fuzzer.h"
+#include <fuzzer/FuzzedDataProvider.h>
+#include <processgroup/sched_policy.h>
+#include "Scheduler/DispSyncSource.h"
+#include "Scheduler/OneShotTimer.h"
+#include "Scheduler/VSyncDispatchTimerQueue.h"
+#include "Scheduler/VSyncPredictor.h"
+#include "Scheduler/VSyncReactor.h"
+#include "surfaceflinger_fuzzers_utils.h"
+
+namespace android::fuzz {
+
+using hardware::graphics::composer::hal::PowerMode;
+
+static constexpr PowerMode kPowerModes[] = {PowerMode::ON, PowerMode::DOZE, PowerMode::OFF,
+                                            PowerMode::DOZE_SUSPEND, PowerMode::ON_SUSPEND};
+
+constexpr uint16_t kRandomStringLength = 256;
+constexpr std::chrono::duration kSyncPeriod(16ms);
+
+template <typename T>
+void dump(T* component, FuzzedDataProvider* fdp) {
+    std::string res = fdp->ConsumeRandomLengthString(kRandomStringLength);
+    component->dump(res);
+}
+
+class SchedulerFuzzer : private VSyncSource::Callback {
+public:
+    SchedulerFuzzer(const uint8_t* data, size_t size) : mFdp(data, size){};
+    void process();
+
+private:
+    void fuzzRefreshRateSelection();
+    void fuzzRefreshRateConfigs();
+    void fuzzVSyncModulator();
+    void fuzzVSyncPredictor();
+    void fuzzVSyncReactor();
+    void fuzzLayerHistory();
+    void fuzzDispSyncSource();
+    void fuzzCallbackToken(scheduler::VSyncDispatchTimerQueue* dispatch);
+    void fuzzVSyncDispatchTimerQueue();
+    void fuzzOneShotTimer();
+    void fuzzEventThread();
+    PhysicalDisplayId getPhysicalDisplayId();
+
+    FuzzedDataProvider mFdp;
+
+protected:
+    void onVSyncEvent(nsecs_t /* when */, nsecs_t /* expectedVSyncTimestamp */,
+                      nsecs_t /* deadlineTimestamp */) {}
+};
+
+PhysicalDisplayId SchedulerFuzzer::getPhysicalDisplayId() {
+    PhysicalDisplayId internalDispId = PhysicalDisplayId::fromPort(111u);
+    PhysicalDisplayId externalDispId = PhysicalDisplayId::fromPort(222u);
+    PhysicalDisplayId randomDispId = PhysicalDisplayId::fromPort(mFdp.ConsumeIntegral<uint16_t>());
+    PhysicalDisplayId dispId64Bit = PhysicalDisplayId::fromEdid(0xffu, 0xffffu, 0xffff'ffffu);
+    PhysicalDisplayId displayId = mFdp.PickValueInArray<PhysicalDisplayId>(
+            {internalDispId, externalDispId, dispId64Bit, randomDispId});
+    return displayId;
+}
+
+void SchedulerFuzzer::fuzzEventThread() {
+    const auto getVsyncPeriod = [](uid_t /* uid */) { return kSyncPeriod.count(); };
+    std::unique_ptr<android::impl::EventThread> thread = std::make_unique<
+            android::impl::EventThread>(std::move(std::make_unique<FuzzImplVSyncSource>()), nullptr,
+                                        nullptr, nullptr, getVsyncPeriod);
+
+    thread->onHotplugReceived(getPhysicalDisplayId(), mFdp.ConsumeBool());
+    sp<EventThreadConnection> connection =
+            new EventThreadConnection(thread.get(), mFdp.ConsumeIntegral<uint16_t>(), nullptr,
+                                      {} /*eventRegistration*/);
+    thread->requestNextVsync(connection);
+    thread->setVsyncRate(mFdp.ConsumeIntegral<uint32_t>() /*rate*/, connection);
+
+    thread->setDuration((std::chrono::nanoseconds)mFdp.ConsumeIntegral<uint64_t>(),
+                        (std::chrono::nanoseconds)mFdp.ConsumeIntegral<uint64_t>());
+    thread->registerDisplayEventConnection(connection);
+    thread->onScreenAcquired();
+    thread->onScreenReleased();
+    dump<android::impl::EventThread>(thread.get(), &mFdp);
+}
+
+void SchedulerFuzzer::fuzzDispSyncSource() {
+    std::unique_ptr<FuzzImplVSyncDispatch> vSyncDispatch =
+            std::make_unique<FuzzImplVSyncDispatch>();
+    std::unique_ptr<scheduler::DispSyncSource> dispSyncSource = std::make_unique<
+            scheduler::DispSyncSource>(*vSyncDispatch,
+                                       (std::chrono::nanoseconds)
+                                               mFdp.ConsumeIntegral<uint64_t>() /*workDuration*/,
+                                       (std::chrono::nanoseconds)mFdp.ConsumeIntegral<uint64_t>()
+                                       /*readyDuration*/,
+                                       mFdp.ConsumeBool(),
+                                       mFdp.ConsumeRandomLengthString(kRandomStringLength).c_str());
+    dispSyncSource->setVSyncEnabled(true);
+    dispSyncSource->setCallback(this);
+    dispSyncSource->setDuration((std::chrono::nanoseconds)mFdp.ConsumeIntegral<uint64_t>(), 0ns);
+    dump<scheduler::DispSyncSource>(dispSyncSource.get(), &mFdp);
+}
+
+void SchedulerFuzzer::fuzzCallbackToken(scheduler::VSyncDispatchTimerQueue* dispatch) {
+    scheduler::VSyncDispatch::CallbackToken tmp = dispatch->registerCallback(
+            [&](auto, auto, auto) {
+                dispatch->schedule(tmp,
+                                   {.workDuration = mFdp.ConsumeIntegral<nsecs_t>(),
+                                    .readyDuration = mFdp.ConsumeIntegral<nsecs_t>(),
+                                    .earliestVsync = mFdp.ConsumeIntegral<nsecs_t>()});
+            },
+            "o.o");
+    dispatch->schedule(tmp,
+                       {.workDuration = mFdp.ConsumeIntegral<nsecs_t>(),
+                        .readyDuration = mFdp.ConsumeIntegral<nsecs_t>(),
+                        .earliestVsync = mFdp.ConsumeIntegral<nsecs_t>()});
+    dispatch->unregisterCallback(tmp);
+    dispatch->cancel(tmp);
+}
+
+void SchedulerFuzzer::fuzzVSyncDispatchTimerQueue() {
+    FuzzImplVSyncTracker stubTracker{mFdp.ConsumeIntegral<nsecs_t>()};
+    scheduler::VSyncDispatchTimerQueue
+            mDispatch{std::make_unique<scheduler::ControllableClock>(), stubTracker,
+                      mFdp.ConsumeIntegral<nsecs_t>() /*dispatchGroupThreshold*/,
+                      mFdp.ConsumeIntegral<nsecs_t>() /*vSyncMoveThreshold*/};
+
+    fuzzCallbackToken(&mDispatch);
+
+    dump<scheduler::VSyncDispatchTimerQueue>(&mDispatch, &mFdp);
+
+    scheduler::VSyncDispatchTimerQueueEntry entry(
+            "fuzz", [](auto, auto, auto) {},
+            mFdp.ConsumeIntegral<nsecs_t>() /*vSyncMoveThreshold*/);
+    entry.update(stubTracker, 0);
+    entry.schedule({.workDuration = mFdp.ConsumeIntegral<nsecs_t>(),
+                    .readyDuration = mFdp.ConsumeIntegral<nsecs_t>(),
+                    .earliestVsync = mFdp.ConsumeIntegral<nsecs_t>()},
+                   stubTracker, 0);
+    entry.disarm();
+    entry.ensureNotRunning();
+    entry.schedule({.workDuration = mFdp.ConsumeIntegral<nsecs_t>(),
+                    .readyDuration = mFdp.ConsumeIntegral<nsecs_t>(),
+                    .earliestVsync = mFdp.ConsumeIntegral<nsecs_t>()},
+                   stubTracker, 0);
+    auto const wakeup = entry.wakeupTime();
+    auto const ready = entry.readyTime();
+    entry.callback(entry.executing(), *wakeup, *ready);
+    entry.addPendingWorkloadUpdate({.workDuration = mFdp.ConsumeIntegral<nsecs_t>(),
+                                    .readyDuration = mFdp.ConsumeIntegral<nsecs_t>(),
+                                    .earliestVsync = mFdp.ConsumeIntegral<nsecs_t>()});
+    dump<scheduler::VSyncDispatchTimerQueueEntry>(&entry, &mFdp);
+}
+
+void SchedulerFuzzer::fuzzVSyncPredictor() {
+    uint16_t now = mFdp.ConsumeIntegral<uint16_t>();
+    uint16_t historySize = mFdp.ConsumeIntegralInRange<uint16_t>(1, UINT16_MAX);
+    uint16_t minimumSamplesForPrediction = mFdp.ConsumeIntegralInRange<uint16_t>(1, UINT16_MAX);
+    scheduler::VSyncPredictor tracker{mFdp.ConsumeIntegral<uint16_t>() /*period*/, historySize,
+                                      minimumSamplesForPrediction,
+                                      mFdp.ConsumeIntegral<uint32_t>() /*outlierTolerancePercent*/};
+    uint16_t period = mFdp.ConsumeIntegral<uint16_t>();
+    tracker.setPeriod(period);
+    for (uint16_t i = 0; i < minimumSamplesForPrediction; ++i) {
+        if (!tracker.needsMoreSamples()) {
+            break;
+        }
+        tracker.addVsyncTimestamp(now += period);
+    }
+    tracker.nextAnticipatedVSyncTimeFrom(now);
+    tracker.resetModel();
+}
+
+void SchedulerFuzzer::fuzzOneShotTimer() {
+    FakeClock* clock = new FakeClock();
+    std::unique_ptr<scheduler::OneShotTimer> idleTimer = std::make_unique<scheduler::OneShotTimer>(
+            mFdp.ConsumeRandomLengthString(kRandomStringLength) /*name*/,
+            (std::chrono::milliseconds)mFdp.ConsumeIntegral<uint8_t>() /*val*/,
+            [] {} /*resetCallback*/, [] {} /*timeoutCallback*/, std::unique_ptr<FakeClock>(clock));
+    idleTimer->start();
+    idleTimer->reset();
+    idleTimer->stop();
+}
+
+void SchedulerFuzzer::fuzzLayerHistory() {
+    TestableSurfaceFlinger flinger;
+    flinger.setupScheduler(std::make_unique<android::mock::VsyncController>(),
+                           std::make_unique<android::mock::VSyncTracker>(),
+                           std::make_unique<android::mock::EventThread>(),
+                           std::make_unique<android::mock::EventThread>());
+    flinger.setupTimeStats(std::make_unique<android::mock::TimeStats>());
+    std::unique_ptr<android::renderengine::RenderEngine> renderEngine =
+            std::make_unique<android::renderengine::mock::RenderEngine>();
+    flinger.setupRenderEngine(std::move(renderEngine));
+    flinger.setupComposer(std::make_unique<android::Hwc2::mock::Composer>());
+
+    scheduler::TestableScheduler* scheduler = flinger.scheduler();
+
+    scheduler::LayerHistory& historyV1 = scheduler->mutableLayerHistory();
+    nsecs_t time1 = systemTime();
+    nsecs_t time2 = time1;
+    uint8_t historySize = mFdp.ConsumeIntegral<uint8_t>();
+
+    sp<FuzzImplLayer> layer1 = new FuzzImplLayer(flinger.flinger());
+    sp<FuzzImplLayer> layer2 = new FuzzImplLayer(flinger.flinger());
+
+    for (int i = 0; i < historySize; ++i) {
+        historyV1.record(layer1.get(), time1, time1,
+                         scheduler::LayerHistory::LayerUpdateType::Buffer);
+        historyV1.record(layer2.get(), time2, time2,
+                         scheduler::LayerHistory::LayerUpdateType::Buffer);
+        time1 += mFdp.PickValueInArray(kVsyncPeriods);
+        time2 += mFdp.PickValueInArray(kVsyncPeriods);
+    }
+    historyV1.summarize(*scheduler->refreshRateConfigs(), time1);
+    historyV1.summarize(*scheduler->refreshRateConfigs(), time2);
+
+    scheduler->createConnection(std::make_unique<android::mock::EventThread>());
+
+    scheduler::ConnectionHandle handle;
+    scheduler->createDisplayEventConnection(handle);
+    scheduler->setDuration(handle, (std::chrono::nanoseconds)mFdp.ConsumeIntegral<uint64_t>(),
+                           (std::chrono::nanoseconds)mFdp.ConsumeIntegral<uint64_t>());
+
+    dump<scheduler::TestableScheduler>(scheduler, &mFdp);
+}
+
+void SchedulerFuzzer::fuzzVSyncReactor() {
+    std::shared_ptr<FuzzImplVSyncTracker> vSyncTracker = std::make_shared<FuzzImplVSyncTracker>();
+    scheduler::VSyncReactor reactor(std::make_unique<ClockWrapper>(
+                                            std::make_shared<FuzzImplClock>()),
+                                    *vSyncTracker, mFdp.ConsumeIntegral<uint8_t>() /*pendingLimit*/,
+                                    false);
+
+    reactor.startPeriodTransition(mFdp.ConsumeIntegral<nsecs_t>());
+    bool periodFlushed = mFdp.ConsumeBool();
+    reactor.addHwVsyncTimestamp(0, std::nullopt, &periodFlushed);
+    reactor.addHwVsyncTimestamp(mFdp.ConsumeIntegral<nsecs_t>() /*newPeriod*/, std::nullopt,
+                                &periodFlushed);
+    sp<Fence> fence = new Fence(memfd_create("fd", MFD_ALLOW_SEALING));
+    std::shared_ptr<FenceTime> ft = std::make_shared<FenceTime>(fence);
+    vSyncTracker->addVsyncTimestamp(mFdp.ConsumeIntegral<nsecs_t>());
+    FenceTime::Snapshot snap(mFdp.ConsumeIntegral<nsecs_t>());
+    ft->applyTrustedSnapshot(snap);
+    reactor.setIgnorePresentFences(mFdp.ConsumeBool());
+    reactor.addPresentFence(ft);
+    dump<scheduler::VSyncReactor>(&reactor, &mFdp);
+}
+
+void SchedulerFuzzer::fuzzVSyncModulator() {
+    enum {
+        SF_OFFSET_LATE,
+        APP_OFFSET_LATE,
+        SF_DURATION_LATE,
+        APP_DURATION_LATE,
+        SF_OFFSET_EARLY,
+        APP_OFFSET_EARLY,
+        SF_DURATION_EARLY,
+        APP_DURATION_EARLY,
+        SF_OFFSET_EARLY_GPU,
+        APP_OFFSET_EARLY_GPU,
+        SF_DURATION_EARLY_GPU,
+        APP_DURATION_EARLY_GPU,
+        HWC_MIN_WORK_DURATION,
+    };
+    using Schedule = scheduler::TransactionSchedule;
+    using nanos = std::chrono::nanoseconds;
+    using VsyncModulator = scheduler::VsyncModulator;
+    using FuzzImplVsyncModulator = scheduler::FuzzImplVsyncModulator;
+    const VsyncModulator::VsyncConfig early{SF_OFFSET_EARLY, APP_OFFSET_EARLY,
+                                            nanos(SF_DURATION_LATE), nanos(APP_DURATION_LATE)};
+    const VsyncModulator::VsyncConfig earlyGpu{SF_OFFSET_EARLY_GPU, APP_OFFSET_EARLY_GPU,
+                                               nanos(SF_DURATION_EARLY), nanos(APP_DURATION_EARLY)};
+    const VsyncModulator::VsyncConfig late{SF_OFFSET_LATE, APP_OFFSET_LATE,
+                                           nanos(SF_DURATION_EARLY_GPU),
+                                           nanos(APP_DURATION_EARLY_GPU)};
+    const VsyncModulator::VsyncConfigSet offsets = {early, earlyGpu, late,
+                                                    nanos(HWC_MIN_WORK_DURATION)};
+    sp<FuzzImplVsyncModulator> vSyncModulator =
+            sp<FuzzImplVsyncModulator>::make(offsets, scheduler::Now);
+    (void)vSyncModulator->setVsyncConfigSet(offsets);
+    (void)vSyncModulator->setTransactionSchedule(Schedule::Late);
+    const auto token = sp<BBinder>::make();
+    (void)vSyncModulator->setTransactionSchedule(Schedule::EarlyStart, token);
+    vSyncModulator->binderDied(token);
+}
+
+void SchedulerFuzzer::fuzzRefreshRateSelection() {
+    TestableSurfaceFlinger flinger;
+    flinger.setupScheduler(std::make_unique<android::mock::VsyncController>(),
+                           std::make_unique<android::mock::VSyncTracker>(),
+                           std::make_unique<android::mock::EventThread>(),
+                           std::make_unique<android::mock::EventThread>());
+
+    sp<Client> client;
+    LayerCreationArgs args(flinger.flinger(), client,
+                           mFdp.ConsumeRandomLengthString(kRandomStringLength) /*name*/,
+                           mFdp.ConsumeIntegral<uint16_t>() /*layerFlags*/, LayerMetadata());
+    sp<Layer> layer = new BufferQueueLayer(args);
+
+    layer->setFrameRateSelectionPriority(mFdp.ConsumeIntegral<int16_t>());
+}
+
+void SchedulerFuzzer::fuzzRefreshRateConfigs() {
+    using RefreshRateConfigs = scheduler::RefreshRateConfigs;
+    using LayerRequirement = RefreshRateConfigs::LayerRequirement;
+    using RefreshRateStats = scheduler::RefreshRateStats;
+    uint16_t minRefreshRate = mFdp.ConsumeIntegralInRange<uint16_t>(1, UINT16_MAX >> 1);
+    uint16_t maxRefreshRate = mFdp.ConsumeIntegralInRange<uint16_t>(minRefreshRate + 1, UINT16_MAX);
+
+    DisplayModeId hwcConfigIndexType = DisplayModeId(mFdp.ConsumeIntegralInRange<uint8_t>(0, 10));
+
+    DisplayModes displayModes;
+    for (uint16_t fps = minRefreshRate; fps < maxRefreshRate; ++fps) {
+        constexpr int32_t kGroup = 0;
+        const auto refreshRate = Fps::fromValue(static_cast<float>(fps));
+        displayModes.push_back(scheduler::createDisplayMode(hwcConfigIndexType, kGroup,
+                                                            refreshRate.getPeriodNsecs()));
+    }
+    auto refreshRateConfigs =
+            std::make_unique<RefreshRateConfigs>(displayModes, hwcConfigIndexType);
+    const RefreshRateConfigs::GlobalSignals globalSignals = {.touch = false, .idle = false};
+    auto layers = std::vector<LayerRequirement>{
+            LayerRequirement{.weight = mFdp.ConsumeFloatingPoint<float>()}};
+    refreshRateConfigs->getBestRefreshRate(layers, globalSignals);
+    layers[0].name = mFdp.ConsumeRandomLengthString(kRandomStringLength);
+    layers[0].ownerUid = mFdp.ConsumeIntegral<uint16_t>();
+    layers[0].desiredRefreshRate = Fps::fromValue(mFdp.ConsumeFloatingPoint<float>());
+    layers[0].vote = mFdp.PickValueInArray(kLayerVoteTypes);
+    auto frameRateOverrides =
+            refreshRateConfigs->getFrameRateOverrides(layers,
+                                                      Fps::fromValue(
+                                                              mFdp.ConsumeFloatingPoint<float>()),
+                                                      globalSignals);
+
+    refreshRateConfigs->setDisplayManagerPolicy(
+            {hwcConfigIndexType,
+             {Fps::fromValue(mFdp.ConsumeFloatingPoint<float>()),
+              Fps::fromValue(mFdp.ConsumeFloatingPoint<float>())}});
+    refreshRateConfigs->setCurrentModeId(hwcConfigIndexType);
+
+    RefreshRateConfigs::isFractionalPairOrMultiple(Fps::fromValue(
+                                                           mFdp.ConsumeFloatingPoint<float>()),
+                                                   Fps::fromValue(
+                                                           mFdp.ConsumeFloatingPoint<float>()));
+    RefreshRateConfigs::getFrameRateDivider(Fps::fromValue(mFdp.ConsumeFloatingPoint<float>()),
+                                            Fps::fromValue(mFdp.ConsumeFloatingPoint<float>()));
+
+    android::mock::TimeStats timeStats;
+    std::unique_ptr<RefreshRateStats> refreshRateStats =
+            std::make_unique<RefreshRateStats>(timeStats,
+                                               Fps::fromValue(mFdp.ConsumeFloatingPoint<float>()),
+                                               PowerMode::OFF);
+    refreshRateStats->setRefreshRate(
+            refreshRateConfigs->getRefreshRateFromModeId(hwcConfigIndexType).getFps());
+    refreshRateStats->setPowerMode(mFdp.PickValueInArray(kPowerModes));
+}
+
+void SchedulerFuzzer::process() {
+    fuzzRefreshRateSelection();
+    fuzzRefreshRateConfigs();
+    fuzzVSyncModulator();
+    fuzzVSyncPredictor();
+    fuzzVSyncReactor();
+    fuzzLayerHistory();
+    fuzzDispSyncSource();
+    fuzzEventThread();
+    fuzzVSyncDispatchTimerQueue();
+    fuzzOneShotTimer();
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+    SchedulerFuzzer schedulerFuzzer(data, size);
+    schedulerFuzzer.process();
+    return 0;
+}
+
+} // namespace android::fuzz
diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.h b/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.h
new file mode 100644
index 0000000..89cf819
--- /dev/null
+++ b/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.h
@@ -0,0 +1,229 @@
+/*
+ * Copyright 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.
+ *
+ */
+
+/*
+    Reference for some of the classes and functions has been taken from unittests
+    present in frameworks/native/services/surfaceflinger/tests/unittests
+*/
+
+#pragma once
+
+#include "Clock.h"
+#include "Layer.h"
+#include "Scheduler/EventThread.h"
+#include "Scheduler/RefreshRateConfigs.h"
+#include "Scheduler/Scheduler.h"
+#include "Scheduler/VSyncTracker.h"
+#include "Scheduler/VsyncModulator.h"
+#include "scheduler/TimeKeeper.h"
+
+namespace android::fuzz {
+
+constexpr int64_t kVsyncPeriods[] = {static_cast<int64_t>(1e9f / 30),
+                                     static_cast<int64_t>(1e9f / 60),
+                                     static_cast<int64_t>(1e9f / 72),
+                                     static_cast<int64_t>(1e9f / 90),
+                                     static_cast<int64_t>(1e9f / 120)};
+
+android::scheduler::RefreshRateConfigs::LayerVoteType kLayerVoteTypes[] =
+        {android::scheduler::RefreshRateConfigs::LayerVoteType::NoVote,
+         android::scheduler::RefreshRateConfigs::LayerVoteType::Min,
+         android::scheduler::RefreshRateConfigs::LayerVoteType::Max,
+         android::scheduler::RefreshRateConfigs::LayerVoteType::Heuristic,
+         android::scheduler::RefreshRateConfigs::LayerVoteType::ExplicitDefault,
+         android::scheduler::RefreshRateConfigs::LayerVoteType::ExplicitExactOrMultiple};
+
+class FuzzImplClock : public android::scheduler::Clock {
+public:
+    nsecs_t now() const { return 1; }
+};
+
+class ClockWrapper : public android::scheduler::Clock {
+public:
+    ClockWrapper(std::shared_ptr<android::scheduler::Clock> const& clock) : mClock(clock) {}
+
+    nsecs_t now() const { return mClock->now(); }
+
+private:
+    std::shared_ptr<android::scheduler::Clock> const mClock;
+};
+
+} // namespace android::fuzz
+
+namespace android {
+
+using namespace std::chrono_literals;
+
+class FakeClock : public Clock {
+public:
+    virtual ~FakeClock() = default;
+    std::chrono::steady_clock::time_point now() const override { return mNow; }
+
+    void advanceTime(std::chrono::nanoseconds delta) { mNow += delta; }
+
+private:
+    std::chrono::steady_clock::time_point mNow;
+};
+
+class FuzzImplLayer : public Layer {
+public:
+    FuzzImplLayer(SurfaceFlinger* flinger, std::string name)
+          : Layer(LayerCreationArgs(flinger, nullptr, std::move(name), 0, {})) {}
+    explicit FuzzImplLayer(SurfaceFlinger* flinger) : FuzzImplLayer(flinger, "FuzzLayer") {}
+
+    const char* getType() const override { return ""; }
+
+    bool isVisible() const override { return true; }
+
+    sp<Layer> createClone() override { return nullptr; }
+};
+
+class FuzzImplVSyncSource : public VSyncSource {
+public:
+    const char* getName() const override { return "fuzz"; }
+
+    void setVSyncEnabled(bool /* enable */) override {}
+
+    void setCallback(Callback* /* callback */) override {}
+
+    void setDuration(std::chrono::nanoseconds /* workDuration */,
+                     std::chrono::nanoseconds /* readyDuration */) override {}
+
+    void dump(std::string& /* result */) const override {}
+};
+
+class FuzzImplVSyncTracker : public scheduler::VSyncTracker {
+public:
+    FuzzImplVSyncTracker(nsecs_t period) { mPeriod = period; }
+
+    FuzzImplVSyncTracker() = default;
+
+    bool addVsyncTimestamp(nsecs_t /* timestamp */) override { return true; }
+
+    nsecs_t nextAnticipatedVSyncTimeFrom(nsecs_t /* timePoint */) const override { return 1; }
+
+    nsecs_t currentPeriod() const override { return 1; }
+
+    void setPeriod(nsecs_t /* period */) override {}
+
+    void resetModel() override {}
+
+    bool needsMoreSamples() const override { return true; }
+
+    bool isVSyncInPhase(nsecs_t /* timePoint */, Fps /* frameRate */) const override {
+        return true;
+    }
+
+    nsecs_t nextVSyncTime(nsecs_t timePoint) const {
+        if (timePoint % mPeriod == 0) {
+            return timePoint;
+        }
+        return (timePoint - (timePoint % mPeriod) + mPeriod);
+    }
+
+    void dump(std::string& /* result */) const override {}
+
+protected:
+    nsecs_t mPeriod;
+};
+
+class FuzzImplVSyncDispatch : public scheduler::VSyncDispatch {
+public:
+    CallbackToken registerCallback(Callback /* callbackFn */,
+                                   std::string /* callbackName */) override {
+        return CallbackToken{};
+    }
+
+    void unregisterCallback(CallbackToken /* token */) override {}
+
+    scheduler::ScheduleResult schedule(CallbackToken /* token */,
+                                       ScheduleTiming /* scheduleTiming */) override {
+        return (scheduler::ScheduleResult)0;
+    }
+
+    scheduler::CancelResult cancel(CallbackToken /* token */) override {
+        return (scheduler::CancelResult)0;
+    }
+
+    void dump(std::string& /* result */) const override {}
+};
+
+} // namespace android
+
+namespace android::scheduler {
+
+DisplayModePtr createDisplayMode(DisplayModeId modeId, int32_t group, int64_t vsyncPeriod,
+                                 ui::Size resolution = ui::Size()) {
+    return DisplayMode::Builder(hal::HWConfigId(modeId.value()))
+            .setId(modeId)
+            .setPhysicalDisplayId(PhysicalDisplayId::fromPort(0))
+            .setVsyncPeriod(int32_t(vsyncPeriod))
+            .setGroup(group)
+            .setHeight(resolution.height)
+            .setWidth(resolution.width)
+            .build();
+}
+
+class ControllableClock : public TimeKeeper {
+public:
+    nsecs_t now() const { return 1; };
+    void alarmAt(std::function<void()> /* callback */, nsecs_t /* time */) override {}
+    void alarmCancel() override {}
+    void dump(std::string& /* result */) const override {}
+
+    void alarmAtDefaultBehavior(std::function<void()> const& callback, nsecs_t time) {
+        mCallback = callback;
+        mNextCallbackTime = time;
+    }
+
+    nsecs_t fakeTime() const { return mCurrentTime; }
+
+    void advanceToNextCallback() {
+        mCurrentTime = mNextCallbackTime;
+        if (mCallback) {
+            mCallback();
+        }
+    }
+
+    void advanceBy(nsecs_t advancement) {
+        mCurrentTime += advancement;
+        if (mCurrentTime >= (mNextCallbackTime + mLag) && mCallback) {
+            mCallback();
+        }
+    };
+
+    void setLag(nsecs_t lag) { mLag = lag; }
+
+private:
+    std::function<void()> mCallback;
+    nsecs_t mNextCallbackTime = 0;
+    nsecs_t mCurrentTime = 0;
+    nsecs_t mLag = 0;
+};
+
+static VsyncModulator::TimePoint Now() {
+    static VsyncModulator::TimePoint now;
+    return now += VsyncModulator::MIN_EARLY_TRANSACTION_TIME;
+}
+
+class FuzzImplVsyncModulator : public VsyncModulator {
+public:
+    FuzzImplVsyncModulator(const VsyncConfigSet& config, Now now) : VsyncModulator(config, now) {}
+
+    void binderDied(const wp<IBinder>& token) { VsyncModulator::binderDied(token); }
+};
+} // namespace android::scheduler