Merge "media: Add level 6+ OMX enums for AVC/H.264"
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index e0e211f..0f987c3 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -444,7 +444,7 @@
     }
 
     virtual bool updateInfo() {
-        mInfo.token = mServerChannel->getToken();
+        mInfo.token = mServerChannel ? mServerChannel->getToken() : nullptr;
         mInfo.name = mName;
         mInfo.layoutParamsFlags = 0;
         mInfo.layoutParamsType = InputWindowInfo::TYPE_APPLICATION;
@@ -474,8 +474,8 @@
     }
 
     void releaseChannel() {
+        mServerChannel.clear();
         InputWindowHandle::releaseChannel();
-        mDispatcher->unregisterInputChannel(mServerChannel);
     }
 protected:
     virtual bool handled() {
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index 2a70293..f514fe3 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -152,6 +152,7 @@
         "Scheduler/MessageQueue.cpp",
         "Scheduler/Scheduler.cpp",
         "Scheduler/SchedulerUtils.cpp",
+        "Scheduler/PhaseOffsets.cpp",
         "StartPropertySetThread.cpp",
         "SurfaceFlinger.cpp",
         "SurfaceInterceptor.cpp",
diff --git a/services/surfaceflinger/Scheduler/DispSync.cpp b/services/surfaceflinger/Scheduler/DispSync.cpp
index 9b2a6fc..075e238 100644
--- a/services/surfaceflinger/Scheduler/DispSync.cpp
+++ b/services/surfaceflinger/Scheduler/DispSync.cpp
@@ -757,18 +757,7 @@
     const uint32_t hwcLatency = 0;
 
     // Ask DispSync when the next refresh will be (CLOCK_MONOTONIC).
-    const nsecs_t nextRefresh = computeNextRefresh(hwcLatency);
-
-    // The DispSync time is already adjusted for the difference between
-    // vsync and reported-vsync (SurfaceFlinger::dispSyncPresentTimeOffset), so
-    // we don't need to factor that in here.  Pad a little to avoid
-    // weird effects if apps might be requesting times right on the edge.
-    nsecs_t extraPadding = 0;
-    if (SurfaceFlinger::vsyncPhaseOffsetNs == 0) {
-        extraPadding = 1000000; // 1ms (6% of 60Hz)
-    }
-
-    return nextRefresh + extraPadding;
+    return computeNextRefresh(hwcLatency);
 }
 
 } // namespace impl
diff --git a/services/surfaceflinger/Scheduler/PhaseOffsets.cpp b/services/surfaceflinger/Scheduler/PhaseOffsets.cpp
new file mode 100644
index 0000000..a0a4455
--- /dev/null
+++ b/services/surfaceflinger/Scheduler/PhaseOffsets.cpp
@@ -0,0 +1,117 @@
+/*
+ * Copyright 2019 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 "PhaseOffsets.h"
+
+#include <cutils/properties.h>
+
+#include "SurfaceFlingerProperties.h"
+
+namespace android {
+using namespace android::sysprop;
+
+namespace scheduler {
+
+PhaseOffsets::~PhaseOffsets() = default;
+
+namespace impl {
+PhaseOffsets::PhaseOffsets() {
+    int64_t vsyncPhaseOffsetNs = vsync_event_phase_offset_ns(1000000);
+
+    int64_t sfVsyncPhaseOffsetNs = vsync_sf_event_phase_offset_ns(1000000);
+
+    char value[PROPERTY_VALUE_MAX];
+    property_get("debug.sf.early_phase_offset_ns", value, "-1");
+    const int earlySfOffsetNs = atoi(value);
+
+    property_get("debug.sf.early_gl_phase_offset_ns", value, "-1");
+    const int earlyGlSfOffsetNs = atoi(value);
+
+    property_get("debug.sf.early_app_phase_offset_ns", value, "-1");
+    const int earlyAppOffsetNs = atoi(value);
+
+    property_get("debug.sf.early_gl_app_phase_offset_ns", value, "-1");
+    const int earlyGlAppOffsetNs = atoi(value);
+
+    property_get("debug.sf.high_fps_early_phase_offset_ns", value, "-1");
+    const int highFpsEarlySfOffsetNs = atoi(value);
+
+    property_get("debug.sf.high_fps_early_gl_phase_offset_ns", value, "-1");
+    const int highFpsEarlyGlSfOffsetNs = atoi(value);
+
+    property_get("debug.sf.high_fps_early_app_phase_offset_ns", value, "-1");
+    const int highFpsEarlyAppOffsetNs = atoi(value);
+
+    property_get("debug.sf.high_fps_early_gl_app_phase_offset_ns", value, "-1");
+    const int highFpsEarlyGlAppOffsetNs = atoi(value);
+
+    // TODO(b/122905996): Define these in device.mk.
+    property_get("debug.sf.high_fps_late_app_phase_offset_ns", value, "1000000");
+    const int highFpsLateAppOffsetNs = atoi(value);
+
+    property_get("debug.sf.high_fps_late_sf_phase_offset_ns", value, "8000000");
+    const int highFpsLateSfOffsetNs = atoi(value);
+
+    mDefaultRefreshRateOffsets.early = {earlySfOffsetNs != -1 ? earlySfOffsetNs
+                                                              : sfVsyncPhaseOffsetNs,
+                                        earlyAppOffsetNs != -1 ? earlyAppOffsetNs
+                                                               : vsyncPhaseOffsetNs};
+    mDefaultRefreshRateOffsets.earlyGl = {earlyGlSfOffsetNs != -1 ? earlyGlSfOffsetNs
+                                                                  : sfVsyncPhaseOffsetNs,
+                                          earlyGlAppOffsetNs != -1 ? earlyGlAppOffsetNs
+                                                                   : vsyncPhaseOffsetNs};
+    mDefaultRefreshRateOffsets.late = {sfVsyncPhaseOffsetNs, vsyncPhaseOffsetNs};
+
+    mHighRefreshRateOffsets.early = {highFpsEarlySfOffsetNs != -1 ? highFpsEarlySfOffsetNs
+                                                                  : highFpsLateAppOffsetNs,
+                                     highFpsEarlyAppOffsetNs != -1 ? highFpsEarlyAppOffsetNs
+                                                                   : highFpsLateSfOffsetNs};
+    mHighRefreshRateOffsets.earlyGl = {highFpsEarlyGlSfOffsetNs != -1 ? highFpsEarlyGlSfOffsetNs
+                                                                      : highFpsLateAppOffsetNs,
+                                       highFpsEarlyGlAppOffsetNs != -1 ? highFpsEarlyGlAppOffsetNs
+                                                                       : highFpsLateSfOffsetNs};
+    mHighRefreshRateOffsets.late = {highFpsLateAppOffsetNs, highFpsLateSfOffsetNs};
+}
+
+PhaseOffsets::Offsets PhaseOffsets::getCurrentOffsets() const {
+    switch (mRefreshRateType) {
+        case RefreshRateConfigs::RefreshRateType::PERFORMANCE:
+            return mHighRefreshRateOffsets;
+        default:
+            return mDefaultRefreshRateOffsets;
+    }
+}
+
+void PhaseOffsets::dump(std::string& result) const {
+    const auto [early, earlyGl, late] = getCurrentOffsets();
+    base::StringAppendF(&result,
+                        "         app phase: %9" PRId64 " ns\t         SF phase: %9" PRId64 " ns\n"
+                        "   early app phase: %9" PRId64 " ns\t   early SF phase: %9" PRId64 " ns\n"
+                        "GL early app phase: %9" PRId64 " ns\tGL early SF phase: %9" PRId64 " ns\n",
+                        late.app, late.sf, early.app, early.sf, earlyGl.app, earlyGl.sf);
+}
+
+nsecs_t PhaseOffsets::getCurrentAppOffset() {
+    return getCurrentOffsets().late.app;
+}
+
+nsecs_t PhaseOffsets::getCurrentSfOffset() {
+    return getCurrentOffsets().late.sf;
+}
+
+} // namespace impl
+} // namespace scheduler
+} // namespace android
diff --git a/services/surfaceflinger/Scheduler/PhaseOffsets.h b/services/surfaceflinger/Scheduler/PhaseOffsets.h
new file mode 100644
index 0000000..cbcaade
--- /dev/null
+++ b/services/surfaceflinger/Scheduler/PhaseOffsets.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include <cinttypes>
+
+#include "RefreshRateConfigs.h"
+#include "VSyncModulator.h"
+
+namespace android {
+namespace scheduler {
+
+/*
+ * This class encapsulates offsets for different refresh rates. Depending
+ * on what refresh rate we are using, and wheter we are composing in GL,
+ * different offsets will help us with latency. This class keeps track of
+ * which mode the device is on, and returns approprate offsets when needed.
+ */
+class PhaseOffsets {
+public:
+    struct Offsets {
+        VSyncModulator::Offsets early;
+        VSyncModulator::Offsets earlyGl;
+        VSyncModulator::Offsets late;
+    };
+
+    virtual ~PhaseOffsets();
+
+    virtual nsecs_t getCurrentAppOffset() = 0;
+    virtual nsecs_t getCurrentSfOffset() = 0;
+    virtual Offsets getCurrentOffsets() const = 0;
+    virtual void setRefreshRateType(RefreshRateConfigs::RefreshRateType refreshRateType) = 0;
+    virtual void dump(std::string& result) const = 0;
+};
+
+namespace impl {
+class PhaseOffsets : public scheduler::PhaseOffsets {
+public:
+    PhaseOffsets();
+
+    nsecs_t getCurrentAppOffset() override;
+    nsecs_t getCurrentSfOffset() override;
+
+    // Returns early, early GL, and late offsets for Apps and SF.
+    Offsets getCurrentOffsets() const override;
+
+    // This function should be called when the device is switching between different
+    // refresh rates, to properly update the offsets.
+    void setRefreshRateType(RefreshRateConfigs::RefreshRateType refreshRateType) override {
+        mRefreshRateType = refreshRateType;
+    }
+
+    // Returns current offsets in human friendly format.
+    void dump(std::string& result) const override;
+
+private:
+    Offsets getmDefaultRefreshRateOffsets() { return mDefaultRefreshRateOffsets; }
+    Offsets getmHighRefreshRateOffsets() { return mHighRefreshRateOffsets; }
+
+    std::atomic<RefreshRateConfigs::RefreshRateType> mRefreshRateType =
+            RefreshRateConfigs::RefreshRateType::DEFAULT;
+
+    Offsets mDefaultRefreshRateOffsets;
+    Offsets mHighRefreshRateOffsets;
+};
+} // namespace impl
+
+} // namespace scheduler
+} // namespace android
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index b003451..00820f1 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -70,7 +70,7 @@
     mEventControlThread = std::make_unique<impl::EventControlThread>(function);
 
     char value[PROPERTY_VALUE_MAX];
-    property_get("debug.sf.set_idle_timer_ms", value, "0");
+    property_get("debug.sf.set_idle_timer_ms", value, "30");
     mSetIdleTimerMs = atoi(value);
 
     if (mSetIdleTimerMs > 0) {
diff --git a/services/surfaceflinger/Scheduler/VSyncModulator.h b/services/surfaceflinger/Scheduler/VSyncModulator.h
index dde0c57..d7ec733 100644
--- a/services/surfaceflinger/Scheduler/VSyncModulator.h
+++ b/services/surfaceflinger/Scheduler/VSyncModulator.h
@@ -18,9 +18,10 @@
 
 #include <utils/Errors.h>
 
+#include <cinttypes>
 #include <mutex>
 
-using namespace android::surfaceflinger;
+#include "Scheduler.h"
 
 namespace android {
 
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index ee202a3..2cf2cd8 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -211,8 +211,6 @@
 constexpr float kSrgbWhiteZ = 1.0891f;
 
 // ---------------------------------------------------------------------------
-int64_t SurfaceFlinger::vsyncPhaseOffsetNs;
-int64_t SurfaceFlinger::sfVsyncPhaseOffsetNs;
 int64_t SurfaceFlinger::dispSyncPresentTimeOffset;
 bool SurfaceFlinger::useHwcForRgbToYuv;
 uint64_t SurfaceFlinger::maxVirtualDisplaySize;
@@ -273,6 +271,7 @@
         mLayersRemoved(false),
         mLayersAdded(false),
         mBootTime(systemTime()),
+        mPhaseOffsets{getFactory().createPhaseOffsets()},
         mVisibleRegionsDirty(false),
         mGeometryInvalid(false),
         mAnimCompositionPending(false),
@@ -298,10 +297,6 @@
       : SurfaceFlinger(factory, SkipInitialization) {
     ALOGI("SurfaceFlinger is starting");
 
-    vsyncPhaseOffsetNs = vsync_event_phase_offset_ns(1000000);
-
-    sfVsyncPhaseOffsetNs = vsync_sf_event_phase_offset_ns(1000000);
-
     hasSyncFramework = running_without_sync_framework(true);
 
     dispSyncPresentTimeOffset = present_time_offset_from_vsync_ns(0);
@@ -400,29 +395,11 @@
     auto listSize = property_get_int32("debug.sf.max_igbp_list_size", int32_t(defaultListSize));
     mMaxGraphicBufferProducerListSize = (listSize > 0) ? size_t(listSize) : defaultListSize;
 
-    property_get("debug.sf.early_phase_offset_ns", value, "-1");
-    const int earlySfOffsetNs = atoi(value);
-
-    property_get("debug.sf.early_gl_phase_offset_ns", value, "-1");
-    const int earlyGlSfOffsetNs = atoi(value);
-
-    property_get("debug.sf.early_app_phase_offset_ns", value, "-1");
-    const int earlyAppOffsetNs = atoi(value);
-
-    property_get("debug.sf.early_gl_app_phase_offset_ns", value, "-1");
-    const int earlyGlAppOffsetNs = atoi(value);
-
     property_get("debug.sf.use_scheduler", value, "0");
     mUseScheduler = atoi(value);
 
-    const VSyncModulator::Offsets earlyOffsets =
-            {earlySfOffsetNs != -1 ? earlySfOffsetNs : sfVsyncPhaseOffsetNs,
-            earlyAppOffsetNs != -1 ? earlyAppOffsetNs : vsyncPhaseOffsetNs};
-    const VSyncModulator::Offsets earlyGlOffsets =
-            {earlyGlSfOffsetNs != -1 ? earlyGlSfOffsetNs : sfVsyncPhaseOffsetNs,
-            earlyGlAppOffsetNs != -1 ? earlyGlAppOffsetNs : vsyncPhaseOffsetNs};
-    mVsyncModulator.setPhaseOffsets(earlyOffsets, earlyGlOffsets,
-            {sfVsyncPhaseOffsetNs, vsyncPhaseOffsetNs});
+    const auto [early, gl, late] = mPhaseOffsets->getCurrentOffsets();
+    mVsyncModulator.setPhaseOffsets(early, gl, late);
 
     // We should be reading 'persist.sys.sf.color_saturation' here
     // but since /data may be encrypted, we need to wait until after vold
@@ -629,7 +606,7 @@
     ALOGI(  "SurfaceFlinger's main thread ready to run. "
             "Initializing graphics H/W...");
 
-    ALOGI("Phase offest NS: %" PRId64 "", vsyncPhaseOffsetNs);
+    ALOGI("Phase offset NS: %" PRId64 "", mPhaseOffsets->getCurrentAppOffset());
 
     Mutex::Autolock _l(mStateLock);
 
@@ -640,13 +617,17 @@
         mScheduler = getFactory().createScheduler([this](bool enabled) {
             setVsyncEnabled(EventThread::DisplayType::Primary, enabled);
         });
+        // TODO(b/113612090): Currently we assume that if scheduler is turned on, then the refresh
+        // rate is 90. Once b/122905403 is completed, this should be updated accordingly.
+        mPhaseOffsets->setRefreshRateType(
+                scheduler::RefreshRateConfigs::RefreshRateType::PERFORMANCE);
 
         mAppConnectionHandle =
-                mScheduler->createConnection("appConnection", SurfaceFlinger::vsyncPhaseOffsetNs,
+                mScheduler->createConnection("appConnection", mPhaseOffsets->getCurrentAppOffset(),
                                              resyncCallback,
                                              impl::EventThread::InterceptVSyncsCallback());
         mSfConnectionHandle =
-                mScheduler->createConnection("sfConnection", SurfaceFlinger::sfVsyncPhaseOffsetNs,
+                mScheduler->createConnection("sfConnection", mPhaseOffsets->getCurrentSfOffset(),
                                              resyncCallback, [this](nsecs_t timestamp) {
                                                  mInterceptor->saveVSyncEvent(timestamp);
                                              });
@@ -657,14 +638,14 @@
     } else {
         mEventThreadSource =
                 std::make_unique<DispSyncSource>(mPrimaryDispSync.get(),
-                                                 SurfaceFlinger::vsyncPhaseOffsetNs, true, "app");
+                                                 mPhaseOffsets->getCurrentAppOffset(), true, "app");
         mEventThread =
                 std::make_unique<impl::EventThread>(mEventThreadSource.get(),
                                                     impl::EventThread::InterceptVSyncsCallback(),
                                                     "appEventThread");
         mSfEventThreadSource =
                 std::make_unique<DispSyncSource>(mPrimaryDispSync.get(),
-                                                 SurfaceFlinger::sfVsyncPhaseOffsetNs, true, "sf");
+                                                 mPhaseOffsets->getCurrentSfOffset(), true, "sf");
 
         mSFEventThread =
                 std::make_unique<impl::EventThread>(mSfEventThreadSource.get(),
@@ -745,8 +726,20 @@
     }
 
     if (mUseScheduler) {
-        mScheduler->setExpiredIdleTimerCallback([this]() { setRefreshRateTo(60.f /* fps */); });
-        mScheduler->setResetIdleTimerCallback([this]() { setRefreshRateTo(90.f /* fps */); });
+        mScheduler->setExpiredIdleTimerCallback([this]() {
+            mPhaseOffsets->setRefreshRateType(
+                    scheduler::RefreshRateConfigs::RefreshRateType::DEFAULT);
+            const auto [early, gl, late] = mPhaseOffsets->getCurrentOffsets();
+            mVsyncModulator.setPhaseOffsets(early, gl, late);
+            setRefreshRateTo(60.f /* fps */);
+        });
+        mScheduler->setResetIdleTimerCallback([this]() {
+            mPhaseOffsets->setRefreshRateType(
+                    scheduler::RefreshRateConfigs::RefreshRateType::PERFORMANCE);
+            const auto [early, gl, late] = mPhaseOffsets->getCurrentOffsets();
+            mVsyncModulator.setPhaseOffsets(early, gl, late);
+            setRefreshRateTo(90.f /* fps */);
+        });
         mRefreshRateStats = std::make_unique<scheduler::RefreshRateStats>(
                 getHwComposer().getConfigs(*display->getId()));
     }
@@ -901,7 +894,7 @@
         info.xdpi = xdpi;
         info.ydpi = ydpi;
         info.fps = 1e9 / hwConfig->getVsyncPeriod();
-        info.appVsyncOffset = vsyncPhaseOffsetNs;
+        info.appVsyncOffset = mPhaseOffsets->getCurrentAppOffset();
 
         // This is how far in advance a buffer must be queued for
         // presentation at a given time.  If you want a buffer to appear
@@ -915,8 +908,8 @@
         //
         // We add an additional 1ms to allow for processing time and
         // differences between the ideal and actual refresh rate.
-        info.presentationDeadline = hwConfig->getVsyncPeriod() -
-                sfVsyncPhaseOffsetNs + 1000000;
+        info.presentationDeadline =
+                hwConfig->getVsyncPeriod() - mPhaseOffsets->getCurrentSfOffset() + 1000000;
 
         // All non-virtual displays are currently considered secure.
         info.secure = true;
@@ -1966,11 +1959,11 @@
                                                 nsecs_t compositeToPresentLatency) {
     // Integer division and modulo round toward 0 not -inf, so we need to
     // treat negative and positive offsets differently.
-    nsecs_t idealLatency = (sfVsyncPhaseOffsetNs > 0)
-            ? (stats.vsyncPeriod - (sfVsyncPhaseOffsetNs % stats.vsyncPeriod))
-            : ((-sfVsyncPhaseOffsetNs) % stats.vsyncPeriod);
+    nsecs_t idealLatency = (mPhaseOffsets->getCurrentSfOffset() > 0)
+            ? (stats.vsyncPeriod - (mPhaseOffsets->getCurrentSfOffset() % stats.vsyncPeriod))
+            : ((-mPhaseOffsets->getCurrentSfOffset()) % stats.vsyncPeriod);
 
-    // Just in case sfVsyncPhaseOffsetNs == -vsyncInterval.
+    // Just in case mPhaseOffsets->getCurrentSfOffset() == -vsyncInterval.
     if (idealLatency <= 0) {
         idealLatency = stats.vsyncPeriod;
     }
@@ -1979,7 +1972,7 @@
     // composition and present times, which often have >1ms of jitter.
     // Reducing jitter is important if an app attempts to extrapolate
     // something (such as user input) to an accurate diasplay time.
-    // Snapping also allows an app to precisely calculate sfVsyncPhaseOffsetNs
+    // Snapping also allows an app to precisely calculate mPhaseOffsets->getCurrentSfOffset()
     // with (presentLatency % interval).
     nsecs_t bias = stats.vsyncPeriod / 2;
     int64_t extraVsyncs = (compositeToPresentLatency - idealLatency + bias) / stats.vsyncPeriod;
@@ -4520,15 +4513,10 @@
 }
 
 void SurfaceFlinger::dumpVSync(std::string& result) const {
-    const auto [sfEarlyOffset, appEarlyOffset] = mVsyncModulator.getEarlyOffsets();
-    const auto [sfEarlyGlOffset, appEarlyGlOffset] = mVsyncModulator.getEarlyGlOffsets();
+    mPhaseOffsets->dump(result);
     StringAppendF(&result,
-                  "         app phase: %9" PRId64 " ns\t         SF phase: %9" PRId64 " ns\n"
-                  "   early app phase: %9" PRId64 " ns\t   early SF phase: %9" PRId64 " ns\n"
-                  "GL early app phase: %9" PRId64 " ns\tGL early SF phase: %9" PRId64 " ns\n"
                   "    present offset: %9" PRId64 " ns\t     VSYNC period: %9" PRId64 " ns\n\n",
-                  vsyncPhaseOffsetNs, sfVsyncPhaseOffsetNs, appEarlyOffset, sfEarlyOffset,
-                  appEarlyGlOffset, sfEarlyGlOffset, dispSyncPresentTimeOffset, getVsyncPeriod());
+                  dispSyncPresentTimeOffset, getVsyncPeriod());
 
     StringAppendF(&result, "Scheduler: %s\n\n", mUseScheduler ? "enabled" : "disabled");
 
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index dfb01fb..a48e811 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -59,6 +59,7 @@
 #include "Scheduler/DispSync.h"
 #include "Scheduler/EventThread.h"
 #include "Scheduler/MessageQueue.h"
+#include "Scheduler/PhaseOffsets.h"
 #include "Scheduler/RefreshRateStats.h"
 #include "Scheduler/Scheduler.h"
 #include "Scheduler/VSyncModulator.h"
@@ -952,7 +953,10 @@
     std::unique_ptr<EventControlThread> mEventControlThread;
     std::unordered_map<DisplayId, sp<IBinder>> mPhysicalDisplayTokens;
 
+    // Calculates correct offsets.
     VSyncModulator mVsyncModulator;
+    // Keeps track of all available phase offsets for different refresh types.
+    std::unique_ptr<scheduler::PhaseOffsets> mPhaseOffsets;
 
     // Can only accessed from the main thread, these members
     // don't need synchronization
diff --git a/services/surfaceflinger/SurfaceFlingerFactory.cpp b/services/surfaceflinger/SurfaceFlingerFactory.cpp
index 77679e3..773a5d1 100644
--- a/services/surfaceflinger/SurfaceFlingerFactory.cpp
+++ b/services/surfaceflinger/SurfaceFlingerFactory.cpp
@@ -33,6 +33,7 @@
 #include "Scheduler/DispSync.h"
 #include "Scheduler/EventControlThread.h"
 #include "Scheduler/MessageQueue.h"
+#include "Scheduler/PhaseOffsets.h"
 #include "Scheduler/Scheduler.h"
 #include "TimeStats/TimeStats.h"
 
@@ -68,6 +69,10 @@
             return std::make_unique<android::impl::MessageQueue>();
         }
 
+        std::unique_ptr<scheduler::PhaseOffsets> createPhaseOffsets() override {
+            return std::make_unique<scheduler::impl::PhaseOffsets>();
+        }
+
         std::unique_ptr<Scheduler> createScheduler(std::function<void(bool)> callback) override {
             return std::make_unique<Scheduler>(callback);
         }
diff --git a/services/surfaceflinger/SurfaceFlingerFactory.h b/services/surfaceflinger/SurfaceFlingerFactory.h
index f747684..ac99e2a 100644
--- a/services/surfaceflinger/SurfaceFlingerFactory.h
+++ b/services/surfaceflinger/SurfaceFlingerFactory.h
@@ -52,6 +52,10 @@
 namespace compositionengine {
 class CompositionEngine;
 } // namespace compositionengine
+
+namespace scheduler {
+class PhaseOffsets;
+} // namespace scheduler
 namespace surfaceflinger {
 
 class NativeWindowSurface;
@@ -66,6 +70,7 @@
             std::function<void(bool)> setVSyncEnabled) = 0;
     virtual std::unique_ptr<HWComposer> createHWComposer(const std::string& serviceName) = 0;
     virtual std::unique_ptr<MessageQueue> createMessageQueue() = 0;
+    virtual std::unique_ptr<scheduler::PhaseOffsets> createPhaseOffsets() = 0;
     virtual std::unique_ptr<Scheduler> createScheduler(std::function<void(bool)> callback) = 0;
     virtual std::unique_ptr<SurfaceInterceptor> createSurfaceInterceptor(SurfaceFlinger*) = 0;
 
diff --git a/services/surfaceflinger/tests/unittests/FakePhaseOffsets.h b/services/surfaceflinger/tests/unittests/FakePhaseOffsets.h
new file mode 100644
index 0000000..0739f15
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/FakePhaseOffsets.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include <gmock/gmock.h>
+
+#include "Scheduler/PhaseOffsets.h"
+
+namespace android {
+namespace scheduler {
+
+class FakePhaseOffsets : public android::scheduler::PhaseOffsets {
+    nsecs_t FAKE_PHASE_OFFSET_NS = 0;
+
+public:
+    FakePhaseOffsets() = default;
+    ~FakePhaseOffsets() = default;
+
+    nsecs_t getCurrentAppOffset() override { return FAKE_PHASE_OFFSET_NS; }
+    nsecs_t getCurrentSfOffset() override { return FAKE_PHASE_OFFSET_NS; }
+
+    // Returns early, early GL, and late offsets for Apps and SF.
+    PhaseOffsets::Offsets getCurrentOffsets() const override {
+        return Offsets{{FAKE_PHASE_OFFSET_NS, FAKE_PHASE_OFFSET_NS},
+                       {FAKE_PHASE_OFFSET_NS, FAKE_PHASE_OFFSET_NS},
+                       {FAKE_PHASE_OFFSET_NS, FAKE_PHASE_OFFSET_NS}};
+    }
+
+    // This function should be called when the device is switching between different
+    // refresh rates, to properly update the offsets.
+    void setRefreshRateType(RefreshRateConfigs::RefreshRateType /*refreshRateType*/) override {}
+
+    // Returns current offsets in human friendly format.
+    void dump(std::string& /*result*/) const override {}
+};
+
+} // namespace scheduler
+} // namespace android
\ No newline at end of file
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index b9b0cf8..3a62c40 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -23,6 +23,7 @@
 #include "ColorLayer.h"
 #include "ContainerLayer.h"
 #include "DisplayDevice.h"
+#include "FakePhaseOffsets.h"
 #include "Layer.h"
 #include "NativeWindowSurface.h"
 #include "StartPropertySetThread.h"
@@ -75,6 +76,10 @@
         return std::make_unique<android::impl::MessageQueue>();
     }
 
+    std::unique_ptr<scheduler::PhaseOffsets> createPhaseOffsets() override {
+        return std::make_unique<scheduler::FakePhaseOffsets>();
+    }
+
     std::unique_ptr<Scheduler> createScheduler(std::function<void(bool)>) override {
         // TODO: Use test-fixture controlled factory
         return nullptr;