SurfaceFlinger: add Refresh Rate overlay

Add an overlay to indicate what is the current refresh rate.
Currently it is implemented by a ColorLayer:
 - Red - Default refresh rate
 - Green - Performance refresh rate

To enable the overlay:
adb shell service call SurfaceFlinger 1034 i32 1
To disable the overlay:
adb shell service call SurfaceFlinger 1034 i32 0

Test: manual
Change-Id: I851f2530e7accacd2cac446b30aa2e0b6d431a92
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index ac1d492..c3324af 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -138,8 +138,9 @@
         "LayerVector.cpp",
         "MonitoredProducer.cpp",
         "NativeWindowSurface.cpp",
-        "RenderArea.cpp",
+        "RefreshRateOverlay.cpp",
         "RegionSamplingThread.cpp",
+        "RenderArea.cpp",
         "Scheduler/DispSync.cpp",
         "Scheduler/DispSyncSource.cpp",
         "Scheduler/EventControlThread.cpp",
diff --git a/services/surfaceflinger/RefreshRateOverlay.cpp b/services/surfaceflinger/RefreshRateOverlay.cpp
new file mode 100644
index 0000000..e70bfe4
--- /dev/null
+++ b/services/surfaceflinger/RefreshRateOverlay.cpp
@@ -0,0 +1,53 @@
+/*
+ * 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 "RefreshRateOverlay.h"
+#include "Client.h"
+#include "Layer.h"
+
+namespace android {
+
+using RefreshRateType = scheduler::RefreshRateConfigs::RefreshRateType;
+
+RefreshRateOverlay::RefreshRateOverlay(SurfaceFlinger& flinger)
+      : mFlinger(flinger), mClient(new Client(&mFlinger)) {
+    createLayer();
+}
+
+bool RefreshRateOverlay::createLayer() {
+    const status_t ret =
+            mFlinger.createLayer(String8("RefreshRateOverlay"), mClient, 0, 0,
+                                 PIXEL_FORMAT_RGBA_8888, ISurfaceComposerClient::eFXSurfaceColor,
+                                 LayerMetadata(), &mIBinder, &mGbp, &mLayer);
+    if (ret) {
+        ALOGE("failed to color layer");
+        return false;
+    }
+
+    mLayer = mClient->getLayerUser(mIBinder);
+    mLayer->setCrop_legacy(Rect(0, 0, 200, 100), true);
+    mLayer->setLayer(INT32_MAX - 2);
+
+    return true;
+}
+
+void RefreshRateOverlay::changeRefreshRate(RefreshRateType type) {
+    const half3& color = (type == RefreshRateType::PERFORMANCE) ? GREEN : RED;
+    mLayer->setColor(color);
+    mFlinger.setTransactionFlags(eTransactionMask);
+}
+
+}; // namespace android
diff --git a/services/surfaceflinger/RefreshRateOverlay.h b/services/surfaceflinger/RefreshRateOverlay.h
new file mode 100644
index 0000000..ce29bc3
--- /dev/null
+++ b/services/surfaceflinger/RefreshRateOverlay.h
@@ -0,0 +1,43 @@
+/*
+ * 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 "SurfaceFlinger.h"
+
+namespace android {
+
+using RefreshRateType = scheduler::RefreshRateConfigs::RefreshRateType;
+
+class RefreshRateOverlay {
+public:
+    RefreshRateOverlay(SurfaceFlinger& flinger);
+
+    void changeRefreshRate(RefreshRateType type);
+
+private:
+    bool createLayer();
+
+    SurfaceFlinger& mFlinger;
+    sp<Client> mClient;
+    sp<Layer> mLayer;
+    sp<IBinder> mIBinder;
+    sp<IGraphicBufferProducer> mGbp;
+
+    const half3 RED = half3(1.0f, 0.0f, 0.0f);
+    const half3 GREEN = half3(0.0f, 1.0f, 0.0f);
+};
+
+}; // namespace android
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index e11ab6d..f51b652 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -84,6 +84,7 @@
 #include "LayerVector.h"
 #include "MonitoredProducer.h"
 #include "NativeWindowSurface.h"
+#include "RefreshRateOverlay.h"
 #include "StartPropertySetThread.h"
 #include "SurfaceFlinger.h"
 #include "SurfaceInterceptor.h"
@@ -128,8 +129,6 @@
 using ui::Hdr;
 using ui::RenderIntent;
 
-using RefreshRateType = scheduler::RefreshRateConfigs::RefreshRateType;
-
 namespace {
 
 #pragma clang diagnostic push
@@ -942,19 +941,18 @@
     return display->getActiveConfig();
 }
 
-void SurfaceFlinger::setDesiredActiveConfig(const sp<IBinder>& displayToken, int mode,
-                                            Scheduler::ConfigEvent event) {
+void SurfaceFlinger::setDesiredActiveConfig(const ActiveConfigInfo& info) {
     ATRACE_CALL();
 
     // Lock is acquired by setRefreshRateTo.
-    const auto display = getDisplayDeviceLocked(displayToken);
+    const auto display = getDisplayDeviceLocked(info.displayToken);
     if (!display) {
-        ALOGE("Attempt to set active config %d for invalid display token %p", mode,
-              displayToken.get());
+        ALOGE("Attempt to set active config %d for invalid display token %p", info.configId,
+              info.displayToken.get());
         return;
     }
     if (display->isVirtual()) {
-        ALOGW("Attempt to set active config %d for virtual display", mode);
+        ALOGW("Attempt to set active config %d for virtual display", info.configId);
         return;
     }
     int currentDisplayPowerMode = display->getPowerMode();
@@ -967,8 +965,9 @@
     // config twice. However event generation config might have changed so we need to update it
     // accordingly
     std::lock_guard<std::mutex> lock(mActiveConfigLock);
-    const Scheduler::ConfigEvent desiredConfig = mDesiredActiveConfig.event | event;
-    mDesiredActiveConfig = ActiveConfigInfo{mode, displayToken, desiredConfig};
+    const Scheduler::ConfigEvent prevConfig = mDesiredActiveConfig.event;
+    mDesiredActiveConfig = info;
+    mDesiredActiveConfig.event = mDesiredActiveConfig.event | prevConfig;
 
     if (!mDesiredActiveConfigChanged) {
         // This is the first time we set the desired
@@ -979,6 +978,10 @@
     }
     mDesiredActiveConfigChanged = true;
     ATRACE_INT("DesiredActiveConfigChanged", mDesiredActiveConfigChanged);
+
+    if (mRefreshRateOverlay) {
+        mRefreshRateOverlay->changeRefreshRate(mDesiredActiveConfig.type);
+    }
 }
 
 status_t SurfaceFlinger::setActiveConfig(const sp<IBinder>& displayToken, int mode) {
@@ -1492,7 +1495,7 @@
     }
 
     mPhaseOffsets->setRefreshRateType(refreshRate);
-    setDesiredActiveConfig(getInternalDisplayTokenLocked(), desiredConfigId, event);
+    setDesiredActiveConfig({refreshRate, desiredConfigId, getInternalDisplayTokenLocked(), event});
 }
 
 void SurfaceFlinger::onHotplugReceived(int32_t sequenceId, hwc2_display_t hwcDisplayId,
@@ -5021,9 +5024,9 @@
         code == IBinder::SYSPROPS_TRANSACTION) {
         return OK;
     }
-    // Numbers from 1000 to 1033 are currently used for backdoors. The code
+    // Numbers from 1000 to 1034 are currently used for backdoors. The code
     // in onTransact verifies that the user is root, and has access to use SF.
-    if (code >= 1000 && code <= 1033) {
+    if (code >= 1000 && code <= 1034) {
         ALOGV("Accessing SurfaceFlinger through backdoor code: %u", code);
         return OK;
     }
@@ -5339,6 +5342,18 @@
                 reply->writeInt32(NO_ERROR);
                 return NO_ERROR;
             }
+            case 1034: {
+                // TODO(b/129297325): expose this via developer menu option
+                n = data.readInt32();
+                if (n && !mRefreshRateOverlay) {
+                    std::lock_guard<std::mutex> lock(mActiveConfigLock);
+                    mRefreshRateOverlay = std::make_unique<RefreshRateOverlay>(*this);
+                    mRefreshRateOverlay->changeRefreshRate(mDesiredActiveConfig.type);
+                } else if (!n) {
+                    mRefreshRateOverlay.reset();
+                }
+                return NO_ERROR;
+            }
         }
     }
     return err;
@@ -5811,8 +5826,8 @@
     for (auto iter = refreshRates.crbegin(); iter != refreshRates.crend(); ++iter) {
         if (iter->second && isConfigAllowed(*displayId, iter->second->configId)) {
             ALOGV("switching to config %d", iter->second->configId);
-            setDesiredActiveConfig(displayToken, iter->second->configId,
-                                   Scheduler::ConfigEvent::Changed);
+            setDesiredActiveConfig({iter->first, iter->second->configId, displayToken,
+                                    Scheduler::ConfigEvent::Changed});
             break;
         }
     }
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 26d0cd1..30fd244 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -90,6 +90,8 @@
 
 namespace android {
 
+using RefreshRateType = scheduler::RefreshRateConfigs::RefreshRateType;
+
 // ---------------------------------------------------------------------------
 
 class Client;
@@ -102,6 +104,7 @@
 class IInputFlinger;
 class InjectVSyncSource;
 class Layer;
+class RefreshRateOverlay;
 class Surface;
 class SurfaceFlingerBE;
 class TimeStats;
@@ -366,6 +369,7 @@
     friend class BufferQueueLayer;
     friend class BufferStateLayer;
     friend class MonitoredProducer;
+    friend class RefreshRateOverlay;
     friend class RegionSamplingThread;
     friend class SurfaceTracing;
 
@@ -528,11 +532,30 @@
     void signalLayerUpdate();
     void signalRefresh();
 
+    struct ActiveConfigInfo {
+        RefreshRateType type;
+        int configId;
+        sp<IBinder> displayToken;
+        Scheduler::ConfigEvent event;
+
+        bool operator!=(const ActiveConfigInfo& other) const {
+            if (type != other.type) {
+                return true;
+            }
+            if (configId != other.configId) {
+                return true;
+            }
+            if (displayToken != other.displayToken) {
+                return true;
+            }
+            return (event != other.event);
+        }
+    };
+
     // called on the main thread in response to initializeDisplays()
     void onInitializeDisplays() REQUIRES(mStateLock);
     // Sets the desired active config bit. It obtains the lock, and sets mDesiredActiveConfig.
-    void setDesiredActiveConfig(const sp<IBinder>& displayToken, int mode,
-                                Scheduler::ConfigEvent event) REQUIRES(mStateLock);
+    void setDesiredActiveConfig(const ActiveConfigInfo& info) REQUIRES(mStateLock);
     // Once HWC has returned the present fence, this sets the active config and a new refresh
     // rate in SF. It also triggers HWC vsync.
     void setActiveConfigInternal() REQUIRES(mStateLock);
@@ -815,8 +838,7 @@
 
     // Sets the refresh rate by switching active configs, if they are available for
     // the desired refresh rate.
-    void setRefreshRateTo(scheduler::RefreshRateConfigs::RefreshRateType,
-                          Scheduler::ConfigEvent event) REQUIRES(mStateLock);
+    void setRefreshRateTo(RefreshRateType, Scheduler::ConfigEvent event) REQUIRES(mStateLock);
 
     bool isConfigAllowed(const DisplayId& displayId, int32_t config);
 
@@ -1134,18 +1156,6 @@
     std::unordered_map<DisplayId, std::unique_ptr<const AllowedDisplayConfigs>> mAllowedConfigs
             GUARDED_BY(mAllowedConfigsLock);
 
-    struct ActiveConfigInfo {
-        int configId;
-        sp<IBinder> displayToken;
-        Scheduler::ConfigEvent event;
-
-        bool operator!=(const ActiveConfigInfo& other) const {
-            if (configId != other.configId) {
-                return true;
-            }
-            return (displayToken != other.displayToken);
-        }
-    };
     std::mutex mActiveConfigLock;
     // This bit is set once we start setting the config. We read from this bit during the
     // process. If at the end, this bit is different than mDesiredActiveConfig, we restart
@@ -1172,6 +1182,8 @@
     sp<SetInputWindowsListener> mSetInputWindowsListener;
     bool mPendingSyncInputWindows GUARDED_BY(mStateLock);
     Hwc2::impl::PowerAdvisor mPowerAdvisor;
+
+    std::unique_ptr<RefreshRateOverlay> mRefreshRateOverlay;
 };
 }; // namespace android