Add plumbing for ADPF Power Efficiency hint

These patches introduce a new power efficiency mode for hint sessions
to the public API, and internally expose a new setMode API for hint
sessions that resembles the setMode API for iPower, to control
different session operating modes.

This set of patches:
 - Updates the PowerHAL AIDL to version 5, and updates relevant bp files
 - Exposes new setPreferPowerEfficiency(bool enabled) method from the
 SDK and NDK
 - Exposes new setMode(int mode, bool enabled) method from PowerHAL AIDL
 and HintManagerService
 - Adds support for new setMode call in PowerHAL

Bug: b/288117936
Test: atest cts/tests/tests/os/src/android/os/cts/PerformanceHintManagerTest.java
Test: atest HintManagerServiceTest
Change-Id: Ia1349e1bd8c4c85276788892b69897b5ef267c03
diff --git a/native/android/Android.bp b/native/android/Android.bp
index 254eb44..7f3792d 100644
--- a/native/android/Android.bp
+++ b/native/android/Android.bp
@@ -46,7 +46,10 @@
 
 cc_library_shared {
     name: "libandroid",
-    defaults: ["libandroid_defaults"],
+    defaults: [
+        "libandroid_defaults",
+        "android.hardware.power-ndk_shared",
+    ],
 
     srcs: [
         "activity_manager.cpp",
@@ -95,7 +98,6 @@
         "libpowermanager",
         "android.hardware.configstore@1.0",
         "android.hardware.configstore-utils",
-        "android.hardware.power-V4-ndk",
         "libnativedisplay",
     ],
 
diff --git a/native/android/libandroid.map.txt b/native/android/libandroid.map.txt
index d74f9b7..b0af09c 100644
--- a/native/android/libandroid.map.txt
+++ b/native/android/libandroid.map.txt
@@ -334,6 +334,7 @@
     APerformanceHint_reportActualWorkDuration; # introduced=Tiramisu
     APerformanceHint_closeSession; # introduced=Tiramisu
     APerformanceHint_setThreads; # introduced=UpsideDownCake
+    APerformanceHint_setPreferPowerEfficiency; # introduced=VanillaIceCream
   local:
     *;
 };
diff --git a/native/android/performance_hint.cpp b/native/android/performance_hint.cpp
index 6198f40..c25df6e 100644
--- a/native/android/performance_hint.cpp
+++ b/native/android/performance_hint.cpp
@@ -17,6 +17,7 @@
 #define LOG_TAG "perf_hint"
 
 #include <aidl/android/hardware/power/SessionHint.h>
+#include <aidl/android/hardware/power/SessionMode.h>
 #include <android/os/IHintManager.h>
 #include <android/os/IHintSession.h>
 #include <android/performance_hint.h>
@@ -36,6 +37,7 @@
 using namespace std::chrono_literals;
 
 using AidlSessionHint = aidl::android::hardware::power::SessionHint;
+using AidlSessionMode = aidl::android::hardware::power::SessionMode;
 
 struct APerformanceHintSession;
 
@@ -72,6 +74,7 @@
     int sendHint(SessionHint hint);
     int setThreads(const int32_t* threadIds, size_t size);
     int getThreadIds(int32_t* const threadIds, size_t* size);
+    int setPreferPowerEfficiency(bool enabled);
 
 private:
     friend struct APerformanceHintManager;
@@ -307,6 +310,18 @@
     return 0;
 }
 
+int APerformanceHintSession::setPreferPowerEfficiency(bool enabled) {
+    binder::Status ret =
+            mHintSession->setMode(static_cast<int32_t>(AidlSessionMode::POWER_EFFICIENCY), enabled);
+
+    if (!ret.isOk()) {
+        ALOGE("%s: HintSession setPreferPowerEfficiency failed: %s", __FUNCTION__,
+              ret.exceptionMessage().c_str());
+        return EPIPE;
+    }
+    return OK;
+}
+
 // ===================================== C API
 APerformanceHintManager* APerformanceHint_getManager() {
     return APerformanceHintManager::getInstance();
@@ -357,6 +372,10 @@
             ->getThreadIds(threadIds, size);
 }
 
+int APerformanceHint_setPreferPowerEfficiency(APerformanceHintSession* session, bool enabled) {
+    return session->setPreferPowerEfficiency(enabled);
+}
+
 void APerformanceHint_setIHintManagerForTesting(void* iManager) {
     delete gHintManagerForTesting;
     gHintManagerForTesting = nullptr;
diff --git a/native/android/tests/performance_hint/PerformanceHintNativeTest.cpp b/native/android/tests/performance_hint/PerformanceHintNativeTest.cpp
index 6f7562b..22d33b1 100644
--- a/native/android/tests/performance_hint/PerformanceHintNativeTest.cpp
+++ b/native/android/tests/performance_hint/PerformanceHintNativeTest.cpp
@@ -56,7 +56,8 @@
                 (const ::std::vector<int64_t>& actualDurationNanos,
                  const ::std::vector<int64_t>& timeStampNanos),
                 (override));
-    MOCK_METHOD(Status, sendHint, (int32_t hints), (override));
+    MOCK_METHOD(Status, sendHint, (int32_t hint), (override));
+    MOCK_METHOD(Status, setMode, (int32_t mode, bool enabled), (override));
     MOCK_METHOD(Status, close, (), (override));
     MOCK_METHOD(IBinder*, onAsBinder, (), (override));
 };
@@ -190,3 +191,51 @@
     result = APerformanceHint_setThreads(session, invalidTids.data(), invalidTids.size());
     EXPECT_EQ(EPERM, result);
 }
+
+TEST_F(PerformanceHintTest, SetPowerEfficient) {
+    APerformanceHintManager* manager = createManager();
+
+    std::vector<int32_t> tids;
+    tids.push_back(1);
+    tids.push_back(2);
+    int64_t targetDuration = 56789L;
+
+    StrictMock<MockIHintSession>* iSession = new StrictMock<MockIHintSession>();
+    sp<IHintSession> session_sp(iSession);
+
+    EXPECT_CALL(*mMockIHintManager, createHintSession(_, Eq(tids), Eq(targetDuration), _))
+            .Times(Exactly(1))
+            .WillRepeatedly(DoAll(SetArgPointee<3>(std::move(session_sp)), Return(Status())));
+
+    APerformanceHintSession* session =
+            APerformanceHint_createSession(manager, tids.data(), tids.size(), targetDuration);
+    ASSERT_TRUE(session);
+
+    EXPECT_CALL(*iSession, setMode(_, Eq(true))).Times(Exactly(1));
+    int result = APerformanceHint_setPreferPowerEfficiency(session, true);
+    EXPECT_EQ(0, result);
+
+    EXPECT_CALL(*iSession, setMode(_, Eq(false))).Times(Exactly(1));
+    result = APerformanceHint_setPreferPowerEfficiency(session, false);
+    EXPECT_EQ(0, result);
+}
+
+TEST_F(PerformanceHintTest, CreateZeroTargetDurationSession) {
+    APerformanceHintManager* manager = createManager();
+
+    std::vector<int32_t> tids;
+    tids.push_back(1);
+    tids.push_back(2);
+    int64_t targetDuration = 0;
+
+    StrictMock<MockIHintSession>* iSession = new StrictMock<MockIHintSession>();
+    sp<IHintSession> session_sp(iSession);
+
+    EXPECT_CALL(*mMockIHintManager, createHintSession(_, Eq(tids), Eq(targetDuration), _))
+            .Times(Exactly(1))
+            .WillRepeatedly(DoAll(SetArgPointee<3>(std::move(session_sp)), Return(Status())));
+
+    APerformanceHintSession* session =
+            APerformanceHint_createSession(manager, tids.data(), tids.size(), targetDuration);
+    ASSERT_TRUE(session);
+}
\ No newline at end of file