sf: Update PowerAdvisor to talk to AIDL Power HAL

Updates the PowerAdvisor to talk to the AIDL Power HAL, and hooks up
the new DISPLAY_UPDATE_IMMINENT Boost present in that HAL.

Test: libsurfaceflinger_unittest
Test: libcompositionengine_test
Test: Manual with ALOGV
Bug: 132390048
Bug: 146453294
Change-Id: I3cb3e8d04303373de24b6dc150ce724aac89407c
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index 4ffdf97..08d7d3f 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -33,6 +33,7 @@
         "android.hardware.graphics.composer@2.4",
         "android.hardware.power@1.0",
         "android.hardware.power@1.3",
+        "android.hardware.power-cpp",
         "libbase",
         "libbinder",
         "libbufferhubqueue",
diff --git a/services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.h b/services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.h
index c5a73f2..e740b13 100644
--- a/services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.h
+++ b/services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.h
@@ -30,6 +30,7 @@
     ~PowerAdvisor() override;
 
     MOCK_METHOD2(setExpensiveRenderingExpected, void(DisplayId displayId, bool expected));
+    MOCK_METHOD0(notifyDisplayUpdateImminent, void());
 };
 
 } // namespace mock
diff --git a/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp b/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
index 039db73..550ec61 100644
--- a/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
+++ b/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
@@ -14,14 +14,23 @@
  * limitations under the License.
  */
 
+//#define LOG_NDEBUG 0
+
 #undef LOG_TAG
 #define LOG_TAG "PowerAdvisor"
 
 #include <cinttypes>
 
+#include <android-base/properties.h>
 #include <utils/Log.h>
 #include <utils/Mutex.h>
 
+#include <android/hardware/power/1.3/IPower.h>
+#include <android/hardware/power/IPower.h>
+#include <binder/IServiceManager.h>
+
+#include "../SurfaceFlingerProperties.h"
+
 #include "PowerAdvisor.h"
 
 namespace android {
@@ -32,11 +41,36 @@
 namespace impl {
 
 namespace V1_0 = android::hardware::power::V1_0;
+namespace V1_3 = android::hardware::power::V1_3;
 using V1_3::PowerHint;
 
+using android::hardware::power::Boost;
+using android::hardware::power::IPower;
+using android::hardware::power::Mode;
+using base::GetIntProperty;
+using scheduler::OneShotTimer;
+
 PowerAdvisor::~PowerAdvisor() = default;
 
-PowerAdvisor::PowerAdvisor() = default;
+namespace {
+int32_t getUpdateTimeout() {
+    // Default to a timeout of 80ms if nothing else is specified
+    static int32_t timeout = sysprop::display_update_imminent_timeout_ms(80);
+    return timeout;
+}
+
+} // namespace
+
+PowerAdvisor::PowerAdvisor()
+      : mUseUpdateImminentTimer(getUpdateTimeout() > 0),
+        mUpdateImminentTimer(
+                OneShotTimer::Interval(getUpdateTimeout()),
+                /* resetCallback */ [this] { mSendUpdateImminent.store(false); },
+                /* timeoutCallback */ [this] { mSendUpdateImminent.store(true); }) {
+    if (mUseUpdateImminentTimer) {
+        mUpdateImminentTimer.start();
+    }
+}
 
 void PowerAdvisor::setExpensiveRenderingExpected(DisplayId displayId, bool expected) {
     if (expected) {
@@ -47,51 +81,170 @@
 
     const bool expectsExpensiveRendering = !mExpensiveDisplays.empty();
     if (mNotifiedExpensiveRendering != expectsExpensiveRendering) {
-        const sp<V1_3::IPower> powerHal = getPowerHal();
-        if (powerHal == nullptr) {
+        HalWrapper* const halWrapper = getPowerHal();
+        if (halWrapper == nullptr) {
             return;
         }
-        auto ret = powerHal->powerHintAsync_1_3(PowerHint::EXPENSIVE_RENDERING,
-                                                expectsExpensiveRendering);
-        // If Power HAL 1.3 was available previously but now fails,
-        // it may restart, so attempt to reconnect next time
-        if (!ret.isOk()) {
+
+        if (!halWrapper->setExpensiveRendering(expectsExpensiveRendering)) {
+            // The HAL has become unavailable; attempt to reconnect later
             mReconnectPowerHal = true;
             return;
         }
+
         mNotifiedExpensiveRendering = expectsExpensiveRendering;
     }
 }
 
-sp<V1_3::IPower> PowerAdvisor::getPowerHal() {
-    static sp<V1_3::IPower> sPowerHal_1_3 = nullptr;
-    static bool sHasPowerHal_1_3 = true;
+void PowerAdvisor::notifyDisplayUpdateImminent() {
+    if (mSendUpdateImminent.load()) {
+        HalWrapper* const halWrapper = getPowerHal();
+        if (halWrapper == nullptr) {
+            return;
+        }
+
+        if (!halWrapper->notifyDisplayUpdateImminent()) {
+            // The HAL has become unavailable; attempt to reconnect later
+            mReconnectPowerHal = true;
+            return;
+        }
+    }
+
+    if (mUseUpdateImminentTimer) {
+        mUpdateImminentTimer.reset();
+    }
+}
+
+class HidlPowerHalWrapper : public PowerAdvisor::HalWrapper {
+public:
+    HidlPowerHalWrapper(sp<V1_3::IPower> powerHal) : mPowerHal(std::move(powerHal)) {}
+
+    ~HidlPowerHalWrapper() override = default;
+
+    static std::unique_ptr<HalWrapper> connect() {
+        // Power HAL 1.3 is not guaranteed to be available, thus we need to query
+        // Power HAL 1.0 first and try to cast it to Power HAL 1.3.
+        // Power HAL 1.0 is always available, thus if we fail to query it, it means
+        // Power HAL is not available temporarily and we should retry later. However,
+        // if Power HAL 1.0 is available and we can't cast it to Power HAL 1.3,
+        // it means Power HAL 1.3 is not available at all, so we should stop trying.
+        sp<V1_3::IPower> powerHal = nullptr;
+        if (sHasPowerHal_1_3) {
+            sp<V1_0::IPower> powerHal_1_0 = V1_0::IPower::getService();
+            if (powerHal_1_0 != nullptr) {
+                // Try to cast to Power HAL 1.3
+                powerHal = V1_3::IPower::castFrom(powerHal_1_0);
+                if (powerHal == nullptr) {
+                    ALOGW("No Power HAL 1.3 service in system");
+                    sHasPowerHal_1_3 = false;
+                } else {
+                    ALOGI("Loaded Power HAL 1.3 service");
+                }
+            }
+        }
+        if (powerHal == nullptr) {
+            return nullptr;
+        }
+
+        return std::make_unique<HidlPowerHalWrapper>(std::move(powerHal));
+    }
+
+    bool setExpensiveRendering(bool enabled) override {
+        ALOGV("HIDL setExpensiveRendering %s", enabled ? "T" : "F");
+        auto ret = mPowerHal->powerHintAsync_1_3(PowerHint::EXPENSIVE_RENDERING, enabled);
+        return ret.isOk();
+    }
+
+    bool notifyDisplayUpdateImminent() override {
+        // Power HAL 1.x doesn't have a notification for this
+        ALOGV("HIDL notifyUpdateImminent received but can't send");
+        return true;
+    }
+
+private:
+    static bool sHasPowerHal_1_3;
+    const sp<V1_3::IPower> mPowerHal = nullptr;
+};
+
+bool HidlPowerHalWrapper::sHasPowerHal_1_3 = true;
+
+class AidlPowerHalWrapper : public PowerAdvisor::HalWrapper {
+public:
+    AidlPowerHalWrapper(sp<IPower> powerHal) : mPowerHal(std::move(powerHal)) {
+        auto ret = mPowerHal->isModeSupported(Mode::EXPENSIVE_RENDERING, &mHasExpensiveRendering);
+        if (!ret.isOk()) {
+            mHasExpensiveRendering = false;
+        }
+
+        ret = mPowerHal->isBoostSupported(Boost::DISPLAY_UPDATE_IMMINENT,
+                                          &mHasDisplayUpdateImminent);
+        if (!ret.isOk()) {
+            mHasDisplayUpdateImminent = false;
+        }
+    }
+
+    ~AidlPowerHalWrapper() override = default;
+
+    static std::unique_ptr<HalWrapper> connect() {
+        // This only waits if the service is actually declared
+        sp<IPower> powerHal = waitForVintfService<IPower>();
+        if (powerHal == nullptr) {
+            return nullptr;
+        }
+        ALOGI("Loaded AIDL Power HAL service");
+
+        return std::make_unique<AidlPowerHalWrapper>(std::move(powerHal));
+    }
+
+    bool setExpensiveRendering(bool enabled) override {
+        ALOGV("AIDL setExpensiveRendering %s", enabled ? "T" : "F");
+        if (!mHasExpensiveRendering) {
+            ALOGV("Skipped sending EXPENSIVE_RENDERING because HAL doesn't support it");
+            return true;
+        }
+
+        auto ret = mPowerHal->setMode(Mode::EXPENSIVE_RENDERING, enabled);
+        return ret.isOk();
+    }
+
+    bool notifyDisplayUpdateImminent() override {
+        ALOGV("AIDL notifyDisplayUpdateImminent");
+        if (!mHasDisplayUpdateImminent) {
+            ALOGV("Skipped sending DISPLAY_UPDATE_IMMINENT because HAL doesn't support it");
+            return true;
+        }
+
+        auto ret = mPowerHal->setBoost(Boost::DISPLAY_UPDATE_IMMINENT, 0);
+        return ret.isOk();
+    }
+
+private:
+    const sp<IPower> mPowerHal = nullptr;
+    bool mHasExpensiveRendering = false;
+    bool mHasDisplayUpdateImminent = false;
+};
+
+PowerAdvisor::HalWrapper* PowerAdvisor::getPowerHal() {
+    static std::unique_ptr<HalWrapper> sHalWrapper = nullptr;
 
     if (mReconnectPowerHal) {
-        sPowerHal_1_3 = nullptr;
+        sHalWrapper = nullptr;
         mReconnectPowerHal = false;
     }
 
-    // Power HAL 1.3 is not guaranteed to be available, thus we need to query
-    // Power HAL 1.0 first and try to cast it to Power HAL 1.3.
-    // Power HAL 1.0 is always available, thus if we fail to query it, it means
-    // Power HAL is not available temporarily and we should retry later. However,
-    // if Power HAL 1.0 is available and we can't cast it to Power HAL 1.3,
-    // it means Power HAL 1.3 is not available at all, so we should stop trying.
-    if (sHasPowerHal_1_3 && sPowerHal_1_3 == nullptr) {
-        sp<V1_0::IPower> powerHal_1_0 = V1_0::IPower::getService();
-        if (powerHal_1_0 != nullptr) {
-            // Try to cast to Power HAL 1.3
-            sPowerHal_1_3 =  V1_3::IPower::castFrom(powerHal_1_0);
-            if (sPowerHal_1_3 == nullptr) {
-                ALOGW("No Power HAL 1.3 service in system");
-                sHasPowerHal_1_3 = false;
-            } else {
-                ALOGI("Loaded Power HAL 1.3 service");
-            }
-        }
+    if (sHalWrapper != nullptr) {
+        return sHalWrapper.get();
     }
-    return sPowerHal_1_3;
+
+    // First attempt to connect to the AIDL Power HAL
+    sHalWrapper = AidlPowerHalWrapper::connect();
+
+    // If that didn't succeed, attempt to connect to the HIDL Power HAL
+    if (sHalWrapper == nullptr) {
+        sHalWrapper = HidlPowerHalWrapper::connect();
+    }
+
+    return sHalWrapper.get();
 }
 
 } // namespace impl
diff --git a/services/surfaceflinger/DisplayHardware/PowerAdvisor.h b/services/surfaceflinger/DisplayHardware/PowerAdvisor.h
index 5aa1f22..957d289 100644
--- a/services/surfaceflinger/DisplayHardware/PowerAdvisor.h
+++ b/services/surfaceflinger/DisplayHardware/PowerAdvisor.h
@@ -22,11 +22,10 @@
 #undef HWC2_INCLUDE_STRINGIFICATION
 #undef HWC2_USE_CPP11
 
+#include <atomic>
 #include <unordered_set>
 
-#include <android/hardware/power/1.3/IPower.h>
-#include <utils/StrongPointer.h>
-
+#include "../Scheduler/OneShotTimer.h"
 #include "DisplayIdentification.h"
 
 namespace android {
@@ -37,27 +36,40 @@
     virtual ~PowerAdvisor();
 
     virtual void setExpensiveRenderingExpected(DisplayId displayId, bool expected) = 0;
+    virtual void notifyDisplayUpdateImminent() = 0;
 };
 
 namespace impl {
 
-namespace V1_3 = android::hardware::power::V1_3;
-
 // PowerAdvisor is a wrapper around IPower HAL which takes into account the
 // full state of the system when sending out power hints to things like the GPU.
 class PowerAdvisor final : public Hwc2::PowerAdvisor {
 public:
+    class HalWrapper {
+    public:
+        virtual ~HalWrapper() = default;
+
+        virtual bool setExpensiveRendering(bool enabled) = 0;
+        virtual bool notifyDisplayUpdateImminent() = 0;
+    };
+
     PowerAdvisor();
     ~PowerAdvisor() override;
 
     void setExpensiveRenderingExpected(DisplayId displayId, bool expected) override;
+    void notifyDisplayUpdateImminent() override;
 
 private:
-    sp<V1_3::IPower> getPowerHal();
+    HalWrapper* getPowerHal();
+
+    bool mReconnectPowerHal = false;
 
     std::unordered_set<DisplayId> mExpensiveDisplays;
     bool mNotifiedExpensiveRendering = false;
-    bool mReconnectPowerHal = false;
+
+    const bool mUseUpdateImminentTimer;
+    std::atomic_bool mSendUpdateImminent = true;
+    scheduler::OneShotTimer mUpdateImminentTimer;
 };
 
 } // namespace impl
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index fbebea0..2acf084 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -1491,11 +1491,13 @@
 
 void SurfaceFlinger::signalTransaction() {
     mScheduler->resetIdleTimer();
+    mPowerAdvisor.notifyDisplayUpdateImminent();
     mEventQueue->invalidate();
 }
 
 void SurfaceFlinger::signalLayerUpdate() {
     mScheduler->resetIdleTimer();
+    mPowerAdvisor.notifyDisplayUpdateImminent();
     mEventQueue->invalidate();
 }
 
@@ -5097,6 +5099,7 @@
 
 void SurfaceFlinger::repaintEverythingForHWC() {
     mRepaintEverything = true;
+    mPowerAdvisor.notifyDisplayUpdateImminent();
     mEventQueue->invalidate();
 }
 
diff --git a/services/surfaceflinger/SurfaceFlingerProperties.cpp b/services/surfaceflinger/SurfaceFlingerProperties.cpp
index 1a611f5..f3352a5 100644
--- a/services/surfaceflinger/SurfaceFlingerProperties.cpp
+++ b/services/surfaceflinger/SurfaceFlingerProperties.cpp
@@ -305,6 +305,14 @@
     return defaultValue;
 }
 
+int32_t display_update_imminent_timeout_ms(int32_t defaultValue) {
+    auto temp = SurfaceFlingerProperties::display_update_imminent_timeout_ms();
+    if (temp.has_value()) {
+        return *temp;
+    }
+    return defaultValue;
+}
+
 #define DISPLAY_PRIMARY_SIZE 3
 
 constexpr float kSrgbRedX = 0.4123f;
diff --git a/services/surfaceflinger/SurfaceFlingerProperties.h b/services/surfaceflinger/SurfaceFlingerProperties.h
index 4c6e191..12c711a 100644
--- a/services/surfaceflinger/SurfaceFlingerProperties.h
+++ b/services/surfaceflinger/SurfaceFlingerProperties.h
@@ -89,6 +89,8 @@
 
 bool use_frame_rate_api(bool defaultValue);
 
+int32_t display_update_imminent_timeout_ms(int32_t defaultValue);
+
 android::ui::DisplayPrimaries getDisplayNativePrimaries();
 } // namespace sysprop
 } // namespace android
diff --git a/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop b/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop
index b19eae6..155f718 100644
--- a/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop
+++ b/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop
@@ -403,3 +403,15 @@
     access: Readonly
     prop_name: "ro.surface_flinger.use_frame_rate_api"
 }
+
+# Sets the timeout used to rate limit DISPLAY_UPDATE_IMMINENT Power HAL notifications.
+# SurfaceFlinger wakeups will trigger this boost whenever they are separated by more than this
+# duration (specified in milliseconds). A value of 0 disables the rate limit, and will result in
+# Power HAL notifications every time SF wakes up.
+prop {
+    api_name: "display_update_imminent_timeout_ms"
+    type: Integer
+    scope: Public
+    access: Readonly
+    prop_name: "ro.surface_flinger.display_update_imminent_timeout_ms"
+}
diff --git a/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt b/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt
index c66523a..e62c127 100644
--- a/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt
+++ b/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt
@@ -36,6 +36,11 @@
     prop_name: "ro.surface_flinger.display_primary_white"
   }
   prop {
+    api_name: "display_update_imminent_timeout_ms"
+    type: Integer
+    prop_name: "ro.surface_flinger.display_update_imminent_timeout_ms"
+  }
+  prop {
     api_name: "enable_protected_contents"
     prop_name: "ro.surface_flinger.protected_contents"
   }
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerAdvisor.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerAdvisor.h
index 7c65f95..fe57c98 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerAdvisor.h
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerAdvisor.h
@@ -30,6 +30,7 @@
     ~PowerAdvisor() override;
 
     MOCK_METHOD2(setExpensiveRenderingExpected, void(DisplayId displayId, bool expected));
+    MOCK_METHOD0(notifyDisplayUpdateImminent, void());
 };
 
 } // namespace mock