Merge "SF: Adding Scheduler information into dumpsys"
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
new file mode 100644
index 0000000..ce1637a
--- /dev/null
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
@@ -0,0 +1,109 @@
+/*
+ * 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 <algorithm>
+#include <numeric>
+
+#include "Scheduler/SchedulerUtils.h"
+#include "android-base/stringprintf.h"
+
+namespace android {
+namespace scheduler {
+
+/**
+ * This class is used to encapsulate configuration for refresh rates. It holds infomation
+ * about available refresh rates on the device, and the mapping between the numbers and human
+ * readable names.
+ */
+class RefreshRateConfigs {
+public:
+    // Enum to indicate which vsync rate to run at. Power saving is intended to be the lowest
+    // (eg. when the screen is in AOD mode or off), default is the old 60Hz, and performance
+    // is the new 90Hz. Eventually we want to have a way for vendors to map these in the configs.
+    enum class RefreshRateType { POWER_SAVING, DEFAULT, PERFORMANCE };
+
+    struct RefreshRate {
+        // Type of the refresh rate.
+        RefreshRateType type;
+        // This config ID corresponds to the position of the config in the vector that is stored
+        // on the device.
+        int configId;
+        // Human readable name of the refresh rate.
+        std::string name;
+    };
+
+    // TODO(b/122916473): Get this information from configs prepared by vendors, instead of
+    // baking them in.
+    explicit RefreshRateConfigs(
+            const std::vector<std::shared_ptr<const HWC2::Display::Config>>& configs) {
+        // This is the rate that HWC encapsulates right now when the screen is off.
+        RefreshRate rate;
+        rate.type = RefreshRateType::POWER_SAVING;
+        rate.configId = SCREEN_OFF_CONFIG_ID;
+        rate.name = "ScreenOff";
+        mRefreshRates.push_back(rate);
+
+        if (configs.size() < 1) {
+            return;
+        }
+
+        std::vector<std::pair<int, nsecs_t>> configIdToVsyncPeriod;
+        for (int i = 0; i < configs.size(); ++i) {
+            configIdToVsyncPeriod.push_back(std::make_pair(i, configs.at(i)->getVsyncPeriod()));
+        }
+        std::sort(configIdToVsyncPeriod.begin(), configIdToVsyncPeriod.end(),
+                  [](const std::pair<int, nsecs_t>& a, const std::pair<int, nsecs_t>& b) {
+                      return a.second > b.second;
+                  });
+
+        nsecs_t vsyncPeriod = configIdToVsyncPeriod.at(0).second;
+        if (vsyncPeriod != 0) {
+            const float fps = std::chrono::nanoseconds(1).count() / vsyncPeriod;
+            rate.type = RefreshRateType::DEFAULT;
+            rate.configId = configIdToVsyncPeriod.at(0).first;
+            rate.name = base::StringPrintf("%2.ffps", fps);
+            mRefreshRates.push_back(rate);
+        }
+        if (configs.size() < 2) {
+            return;
+        }
+
+        vsyncPeriod = configIdToVsyncPeriod.at(1).second;
+        if (vsyncPeriod != 0) {
+            const float fps = std::chrono::nanoseconds(1).count() / vsyncPeriod;
+            rate.type = RefreshRateType::PERFORMANCE;
+            rate.configId = configIdToVsyncPeriod.at(1).first;
+            rate.name = base::StringPrintf("%2.ffps", fps);
+            mRefreshRates.push_back(rate);
+        }
+
+        for (auto refreshRate : mRefreshRates) {
+            ALOGV("type: %d, id: %d, name: %s", refreshRate.type, refreshRate.configId,
+                  refreshRate.name.c_str());
+        }
+    }
+    ~RefreshRateConfigs() = default;
+
+    const std::vector<RefreshRate>& getRefreshRates() { return mRefreshRates; }
+
+private:
+    std::vector<RefreshRate> mRefreshRates;
+};
+
+} // namespace scheduler
+} // namespace android
\ No newline at end of file
diff --git a/services/surfaceflinger/Scheduler/RefreshRateStats.h b/services/surfaceflinger/Scheduler/RefreshRateStats.h
new file mode 100644
index 0000000..cd81e4d
--- /dev/null
+++ b/services/surfaceflinger/Scheduler/RefreshRateStats.h
@@ -0,0 +1,146 @@
+/*
+ * 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 <numeric>
+
+#include "Scheduler/RefreshRateConfigs.h"
+#include "Scheduler/SchedulerUtils.h"
+
+#include "android-base/stringprintf.h"
+#include "utils/Timers.h"
+
+namespace android {
+namespace scheduler {
+
+/**
+ * Class to encapsulate statistics about refresh rates that the display is using. When the power
+ * mode is set to HWC_POWER_MODE_NORMAL, SF is switching between refresh rates that are stored in
+ * the device's configs. Otherwise, we assume the HWC is running in power saving mode under the
+ * hood (eg. the device is in DOZE, or screen off mode).
+ */
+class RefreshRateStats {
+    static constexpr int64_t MS_PER_S = 1000;
+    static constexpr int64_t MS_PER_MIN = 60 * MS_PER_S;
+    static constexpr int64_t MS_PER_HOUR = 60 * MS_PER_MIN;
+    static constexpr int64_t MS_PER_DAY = 24 * MS_PER_HOUR;
+
+public:
+    explicit RefreshRateStats(
+            const std::vector<std::shared_ptr<const HWC2::Display::Config>>& configs)
+          : mRefreshRateConfigs(std::make_unique<RefreshRateConfigs>(configs)),
+            mPreviousRecordedTime(systemTime()) {}
+    ~RefreshRateStats() = default;
+
+    // Sets power mode. We only collect the information when the power mode is not
+    // HWC_POWER_MODE_NORMAL. When power mode is HWC_POWER_MODE_NORMAL, we collect the stats based
+    // on config mode.
+    void setPowerMode(int mode) {
+        if (mCurrentPowerMode == mode) {
+            return;
+        }
+        // If power mode is normal, the time is going to be recorded under config modes.
+        if (mode == HWC_POWER_MODE_NORMAL) {
+            mCurrentPowerMode = mode;
+            return;
+        }
+        flushTime();
+        mCurrentPowerMode = mode;
+    }
+
+    // Sets config mode. If the mode has changed, it records how much time was spent in the previous
+    // mode.
+    void setConfigMode(int mode) {
+        if (mCurrentConfigMode == mode) {
+            return;
+        }
+        flushTime();
+        mCurrentConfigMode = mode;
+    }
+
+    // Returns a map between human readable refresh rate and number of seconds the device spent in
+    // that mode.
+    std::unordered_map<std::string, int64_t> getTotalTimes() {
+        // If the power mode is on, then we are probably switching between the config modes. If
+        // it's not then the screen is probably off. Make sure to flush times before printing
+        // them.
+        flushTime();
+
+        std::unordered_map<std::string, int64_t> totalTime;
+        for (auto config : mRefreshRateConfigs->getRefreshRates()) {
+            if (mConfigModesTotalTime.find(config.configId) != mConfigModesTotalTime.end()) {
+                totalTime[config.name] = mConfigModesTotalTime.at(config.configId);
+            }
+        }
+        return totalTime;
+    }
+
+    // Traverses through the map of config modes and returns how long they've been running in easy
+    // to read format.
+    std::string doDump() {
+        std::ostringstream stream;
+        stream << "+  Refresh rate: running time in seconds\n";
+        for (auto stats : getTotalTimes()) {
+            stream << stats.first.c_str() << ": " << getDateFormatFromMs(stats.second) << "\n";
+        }
+        return stream.str();
+    }
+
+private:
+    void flushTime() {
+        // Normal power mode is counted under different config modes.
+        if (mCurrentPowerMode == HWC_POWER_MODE_NORMAL) {
+            flushTimeForMode(mCurrentConfigMode);
+        } else {
+            flushTimeForMode(SCREEN_OFF_CONFIG_ID);
+        }
+    }
+
+    // Calculates the time that passed in ms between the last time we recorded time and the time
+    // this method was called.
+    void flushTimeForMode(int mode) {
+        nsecs_t currentTime = systemTime();
+        int64_t timeElapsedMs = ns2ms(currentTime - mPreviousRecordedTime);
+        mPreviousRecordedTime = currentTime;
+
+        mConfigModesTotalTime[mode] += timeElapsedMs;
+    }
+
+    // Formats the time in milliseconds into easy to read format.
+    static std::string getDateFormatFromMs(int64_t timeMs) {
+        auto [days, dayRemainderMs] = std::div(timeMs, MS_PER_DAY);
+        auto [hours, hourRemainderMs] = std::div(dayRemainderMs, MS_PER_HOUR);
+        auto [mins, minsRemainderMs] = std::div(hourRemainderMs, MS_PER_MIN);
+        auto [sec, secRemainderMs] = std::div(minsRemainderMs, MS_PER_S);
+        return base::StringPrintf("%" PRId64 "d%02" PRId64 ":%02" PRId64 ":%02" PRId64
+                                  ".%03" PRId64,
+                                  days, hours, mins, sec, secRemainderMs);
+    }
+
+    // Keeps information about refresh rate configs that device has.
+    std::unique_ptr<RefreshRateConfigs> mRefreshRateConfigs;
+
+    int64_t mCurrentConfigMode = 0;
+    int32_t mCurrentPowerMode = HWC_POWER_MODE_OFF;
+
+    std::unordered_map<int /* power mode */, int64_t /* duration in ms */> mConfigModesTotalTime;
+
+    nsecs_t mPreviousRecordedTime;
+};
+
+} // namespace scheduler
+} // namespace android
\ No newline at end of file
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 0d587dd..f4191e6 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -352,4 +352,10 @@
     }
 }
 
+std::string Scheduler::doDump() {
+    std::ostringstream stream;
+    stream << "+  Idle timer interval: " << mSetIdleTimerMs << " ms" << std::endl;
+    return stream.str();
+}
+
 } // namespace android
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index ba18d21..435fd14 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -118,6 +118,8 @@
     void setExpiredIdleTimerCallback(const ExpiredIdleTimerCallback& expiredTimerCallback);
     // Callback that gets invoked once the idle timer is reset.
     void setResetIdleTimerCallback(const ResetIdleTimerCallback& resetTimerCallback);
+    // Returns relevant information about Scheduler for dumpsys purposes.
+    std::string doDump();
 
 protected:
     virtual std::unique_ptr<EventThread> makeEventThread(
diff --git a/services/surfaceflinger/Scheduler/SchedulerUtils.h b/services/surfaceflinger/Scheduler/SchedulerUtils.h
index 17c57db..edd23de 100644
--- a/services/surfaceflinger/Scheduler/SchedulerUtils.h
+++ b/services/surfaceflinger/Scheduler/SchedulerUtils.h
@@ -26,6 +26,11 @@
 // about layers.
 static constexpr size_t ARRAY_SIZE = 30;
 
+// This number is used to have a place holder for when the screen is not NORMAL/ON. Currently
+// the config is not visible to SF, and is completely maintained by HWC. However, we would
+// still like to keep track of time when the device is in this config.
+static constexpr int SCREEN_OFF_CONFIG_ID = -1;
+
 // Calculates the statistical mean (average) in the data structure (array, vector). The
 // function does not modify the contents of the array.
 template <typename T>
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 3f6298f..8454ce3 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -737,6 +737,8 @@
     if (mUseScheduler) {
         mScheduler->setExpiredIdleTimerCallback([this]() { setRefreshRateTo(60.f /* fps */); });
         mScheduler->setResetIdleTimerCallback([this]() { setRefreshRateTo(90.f /* fps */); });
+        mRefreshRateStats = std::make_unique<scheduler::RefreshRateStats>(
+                getHwComposer().getConfigs(*display->getId()));
     }
 
     ALOGV("Done initializing");
@@ -987,6 +989,9 @@
         // Don't update config if we are already running in the desired mode.
         return;
     }
+    if (mUseScheduler) {
+        mRefreshRateStats->setConfigMode(mode);
+    }
 
     const auto displayId = display->getId();
     LOG_ALWAYS_FATAL_IF(!displayId);
@@ -4327,6 +4332,10 @@
 
     if (display->isPrimary()) {
         mTimeStats->setPowerMode(mode);
+        if (mUseScheduler) {
+            // Update refresh rate stats.
+            mRefreshRateStats->setPowerMode(mode);
+        }
     }
 
     ALOGD("Finished setting power mode %d on display %s", mode, to_string(*displayId).c_str());
@@ -4952,6 +4961,15 @@
         result.append(mVrFlinger->Dump());
         result.append("\n");
     }
+
+    /**
+     * Scheduler dump state.
+     */
+    if (mUseScheduler) {
+        result.append("\nScheduler state:\n");
+        result.append(mScheduler->doDump() + "\n");
+        result.append(mRefreshRateStats->doDump() + "\n");
+    }
 }
 
 const Vector<sp<Layer>>& SurfaceFlinger::getLayerSortedByZForHwcDisplay(DisplayId displayId) {
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 499ebcd..28ed004 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/RefreshRateStats.h"
 #include "Scheduler/Scheduler.h"
 #include "Scheduler/VSyncModulator.h"
 #include "SurfaceFlingerFactory.h"
@@ -1037,11 +1038,16 @@
     SurfaceFlingerBE mBE;
     std::unique_ptr<compositionengine::CompositionEngine> mCompositionEngine;
 
+    /* ------------------------------------------------------------------------
+     * Scheduler
+     */
     bool mUseScheduler = false;
     std::unique_ptr<Scheduler> mScheduler;
     sp<Scheduler::ConnectionHandle> mAppConnectionHandle;
     sp<Scheduler::ConnectionHandle> mSfConnectionHandle;
+    std::unique_ptr<scheduler::RefreshRateStats> mRefreshRateStats;
 
+    /* ------------------------------------------------------------------------ */
     sp<IInputFlinger> mInputFlinger;
 
     InputWindowCommands mInputWindowCommands;