Fixes in power benchmarks

- Add support check before running PowerHalAidlBenchmarks for setBoost
  and setMode, to avoid testing unsupported values and getting the HAL
  in a bad state.
- Introduce loop breaks when a binder call fails, since SkipWithError
  is not enough to end the loop early and might cause test timeout if
  we try to interact with a HAL in a bad state.
- Move PauseTiming/ResumeTimings to wrap one-way call delays only, as
  this API is expensive and should be used sparsely (and it's needed
  there to avoid filling up the one-way binder queue).
- Make sure we close all sessions in createHintSession tests.
- Use ndk::enum_range in AIDL enums to cover all available boost and
  mode values.

Fix: 351008375
Flag: EXEMPT test only
Change-Id: I6b277d60767f5928e397765b7dcabd709c4f8953
Test: libpowermanager_benchmarks
diff --git a/services/powermanager/benchmarks/PowerHalAidlBenchmarks.cpp b/services/powermanager/benchmarks/PowerHalAidlBenchmarks.cpp
index 61ab47a..3a1b426 100644
--- a/services/powermanager/benchmarks/PowerHalAidlBenchmarks.cpp
+++ b/services/powermanager/benchmarks/PowerHalAidlBenchmarks.cpp
@@ -40,10 +40,10 @@
 using namespace std::chrono_literals;
 
 // Values from Boost.aidl and Mode.aidl.
-static constexpr int64_t FIRST_BOOST = static_cast<int64_t>(Boost::INTERACTION);
-static constexpr int64_t LAST_BOOST = static_cast<int64_t>(Boost::CAMERA_SHOT);
-static constexpr int64_t FIRST_MODE = static_cast<int64_t>(Mode::DOUBLE_TAP_TO_WAKE);
-static constexpr int64_t LAST_MODE = static_cast<int64_t>(Mode::CAMERA_STREAMING_HIGH);
+static constexpr int64_t FIRST_BOOST = static_cast<int64_t>(*ndk::enum_range<Boost>().begin());
+static constexpr int64_t LAST_BOOST = static_cast<int64_t>(*(ndk::enum_range<Boost>().end()-1));
+static constexpr int64_t FIRST_MODE = static_cast<int64_t>(*ndk::enum_range<Mode>().begin());
+static constexpr int64_t LAST_MODE = static_cast<int64_t>(*(ndk::enum_range<Mode>().end()-1));
 
 class DurationWrapper : public WorkDuration {
 public:
@@ -81,14 +81,17 @@
         return;
     }
 
-    while (state.KeepRunning()) {
+    for (auto _ : state) {
         ret = (*hal.*fn)(std::forward<Args1>(args1)...);
-        state.PauseTiming();
-        if (!ret.isOk()) state.SkipWithError(ret.getDescription().c_str());
-        if (delay > 0us) {
-            testDelaySpin(std::chrono::duration_cast<std::chrono::duration<float>>(delay).count());
+        if (!ret.isOk()) {
+            state.SkipWithError(ret.getDescription().c_str());
+            break;
         }
-        state.ResumeTiming();
+        if (delay > 0us) {
+            state.PauseTiming();
+            testDelaySpin(std::chrono::duration_cast<std::chrono::duration<float>>(delay).count());
+            state.ResumeTiming();
+        }
     }
 }
 
@@ -123,14 +126,15 @@
         return;
     }
 
-    while (state.KeepRunning()) {
+    for (auto _ : state) {
         ret = (*session.*fn)(std::forward<Args1>(args1)...);
-        state.PauseTiming();
-        if (!ret.isOk()) state.SkipWithError(ret.getDescription().c_str());
-        if (ONEWAY_API_DELAY > 0us) {
-            testDelaySpin(std::chrono::duration_cast<std::chrono::duration<float>>(ONEWAY_API_DELAY)
-                                  .count());
+        if (!ret.isOk()) {
+            state.SkipWithError(ret.getDescription().c_str());
+            break;
         }
+        state.PauseTiming();
+        testDelaySpin(std::chrono::duration_cast<std::chrono::duration<float>>(ONEWAY_API_DELAY)
+                                .count());
         state.ResumeTiming();
     }
     session->close();
@@ -150,11 +154,41 @@
 
 static void BM_PowerHalAidlBenchmarks_setBoost(benchmark::State& state) {
     Boost boost = static_cast<Boost>(state.range(0));
+    bool isSupported;
+    std::shared_ptr<IPower> hal = PowerHalLoader::loadAidl();
+
+    if (hal == nullptr) {
+        ALOGV("Power HAL not available, skipping test...");
+        state.SkipWithMessage("Power HAL unavailable");
+        return;
+    }
+
+    ndk::ScopedAStatus ret = hal->isBoostSupported(boost, &isSupported);
+    if (!ret.isOk() || !isSupported) {
+        state.SkipWithMessage("operation unsupported");
+        return;
+    }
+
     runBenchmark(state, ONEWAY_API_DELAY, &IPower::setBoost, boost, 1);
 }
 
 static void BM_PowerHalAidlBenchmarks_setMode(benchmark::State& state) {
     Mode mode = static_cast<Mode>(state.range(0));
+    bool isSupported;
+    std::shared_ptr<IPower> hal = PowerHalLoader::loadAidl();
+
+    if (hal == nullptr) {
+        ALOGV("Power HAL not available, skipping test...");
+        state.SkipWithMessage("Power HAL unavailable");
+        return;
+    }
+
+    ndk::ScopedAStatus ret = hal->isModeSupported(mode, &isSupported);
+    if (!ret.isOk() || !isSupported) {
+        state.SkipWithMessage("operation unsupported");
+        return;
+    }
+
     runBenchmark(state, ONEWAY_API_DELAY, &IPower::setMode, mode, false);
 }
 
@@ -178,12 +212,20 @@
         ALOGV("Power HAL does not support this operation, skipping test...");
         state.SkipWithMessage("operation unsupported");
         return;
+    } else if (!ret.isOk()) {
+        state.SkipWithError(ret.getDescription().c_str());
+        return;
+    } else {
+        appSession->close();
     }
 
-    while (state.KeepRunning()) {
+    for (auto _ : state) {
         ret = hal->createHintSession(tgid, uid, threadIds, durationNanos, &appSession);
+        if (!ret.isOk()) {
+            state.SkipWithError(ret.getDescription().c_str());
+            break;
+        }
         state.PauseTiming();
-        if (!ret.isOk()) state.SkipWithError(ret.getDescription().c_str());
         appSession->close();
         state.ResumeTiming();
     }
diff --git a/services/powermanager/benchmarks/PowerHalControllerBenchmarks.cpp b/services/powermanager/benchmarks/PowerHalControllerBenchmarks.cpp
index effddda..0fda686 100644
--- a/services/powermanager/benchmarks/PowerHalControllerBenchmarks.cpp
+++ b/services/powermanager/benchmarks/PowerHalControllerBenchmarks.cpp
@@ -19,9 +19,9 @@
 #include <aidl/android/hardware/power/Boost.h>
 #include <aidl/android/hardware/power/Mode.h>
 #include <benchmark/benchmark.h>
+#include <chrono>
 #include <powermanager/PowerHalController.h>
 #include <testUtil.h>
-#include <chrono>
 
 using aidl::android::hardware::power::Boost;
 using aidl::android::hardware::power::Mode;
@@ -32,10 +32,10 @@
 using namespace std::chrono_literals;
 
 // Values from Boost.aidl and Mode.aidl.
-static constexpr int64_t FIRST_BOOST = static_cast<int64_t>(Boost::INTERACTION);
-static constexpr int64_t LAST_BOOST = static_cast<int64_t>(Boost::CAMERA_SHOT);
-static constexpr int64_t FIRST_MODE = static_cast<int64_t>(Mode::DOUBLE_TAP_TO_WAKE);
-static constexpr int64_t LAST_MODE = static_cast<int64_t>(Mode::CAMERA_STREAMING_HIGH);
+static constexpr int64_t FIRST_BOOST = static_cast<int64_t>(*ndk::enum_range<Boost>().begin());
+static constexpr int64_t LAST_BOOST = static_cast<int64_t>(*(ndk::enum_range<Boost>().end()-1));
+static constexpr int64_t FIRST_MODE = static_cast<int64_t>(*ndk::enum_range<Mode>().begin());
+static constexpr int64_t LAST_MODE = static_cast<int64_t>(*(ndk::enum_range<Mode>().end()-1));
 
 // Delay between oneway method calls to avoid overflowing the binder buffers.
 static constexpr std::chrono::microseconds ONEWAY_API_DELAY = 100us;
@@ -43,11 +43,27 @@
 template <typename T, class... Args0, class... Args1>
 static void runBenchmark(benchmark::State& state, HalResult<T> (PowerHalController::*fn)(Args0...),
                          Args1&&... args1) {
-    while (state.KeepRunning()) {
-        PowerHalController controller;
+    PowerHalController initController;
+    HalResult<T> result = (initController.*fn)(std::forward<Args1>(args1)...);
+    if (result.isFailed()) {
+        state.SkipWithError(result.errorMessage());
+        return;
+    } else if (result.isUnsupported()) {
+        ALOGV("Power HAL does not support this operation, skipping test...");
+        state.SkipWithMessage("operation unsupported");
+        return;
+    }
+
+    for (auto _ : state) {
+        PowerHalController controller; // new controller to avoid caching
         HalResult<T> ret = (controller.*fn)(std::forward<Args1>(args1)...);
+        if (ret.isFailed()) {
+            state.SkipWithError(ret.errorMessage());
+            break;
+        }
         state.PauseTiming();
-        if (ret.isFailed()) state.SkipWithError("Power HAL request failed");
+        testDelaySpin(
+                std::chrono::duration_cast<std::chrono::duration<float>>(ONEWAY_API_DELAY).count());
         state.ResumeTiming();
     }
 }
@@ -57,22 +73,27 @@
                                HalResult<T> (PowerHalController::*fn)(Args0...), Args1&&... args1) {
     PowerHalController controller;
     // First call out of test, to cache HAL service and isSupported result.
-    (controller.*fn)(std::forward<Args1>(args1)...);
+    HalResult<T> result = (controller.*fn)(std::forward<Args1>(args1)...);
+    if (result.isFailed()) {
+        state.SkipWithError(result.errorMessage());
+        return;
+    } else if (result.isUnsupported()) {
+        ALOGV("Power HAL does not support this operation, skipping test...");
+        state.SkipWithMessage("operation unsupported");
+        return;
+    }
 
-    while (state.KeepRunning()) {
+    for (auto _ : state) {
         HalResult<T> ret = (controller.*fn)(std::forward<Args1>(args1)...);
-        state.PauseTiming();
         if (ret.isFailed()) {
-            state.SkipWithError("Power HAL request failed");
+            state.SkipWithError(ret.errorMessage());
+            break;
         }
-        testDelaySpin(
-                std::chrono::duration_cast<std::chrono::duration<float>>(ONEWAY_API_DELAY).count());
-        state.ResumeTiming();
     }
 }
 
 static void BM_PowerHalControllerBenchmarks_init(benchmark::State& state) {
-    while (state.KeepRunning()) {
+    for (auto _ : state) {
         PowerHalController controller;
         controller.init();
     }
@@ -90,12 +111,12 @@
 
 static void BM_PowerHalControllerBenchmarks_setBoost(benchmark::State& state) {
     Boost boost = static_cast<Boost>(state.range(0));
-    runBenchmark(state, &PowerHalController::setBoost, boost, 0);
+    runBenchmark(state, &PowerHalController::setBoost, boost, 1);
 }
 
 static void BM_PowerHalControllerBenchmarks_setBoostCached(benchmark::State& state) {
     Boost boost = static_cast<Boost>(state.range(0));
-    runCachedBenchmark(state, &PowerHalController::setBoost, boost, 0);
+    runCachedBenchmark(state, &PowerHalController::setBoost, boost, 1);
 }
 
 static void BM_PowerHalControllerBenchmarks_setMode(benchmark::State& state) {
diff --git a/services/powermanager/benchmarks/PowerHalHidlBenchmarks.cpp b/services/powermanager/benchmarks/PowerHalHidlBenchmarks.cpp
index bcb376b..95fd0c2 100644
--- a/services/powermanager/benchmarks/PowerHalHidlBenchmarks.cpp
+++ b/services/powermanager/benchmarks/PowerHalHidlBenchmarks.cpp
@@ -54,14 +54,17 @@
         return;
     }
 
-    while (state.KeepRunning()) {
+    for (auto _ : state) {
         Return<R> ret = (*hal.*fn)(std::forward<Args1>(args1)...);
-        state.PauseTiming();
-        if (!ret.isOk()) state.SkipWithError(ret.description().c_str());
-        if (delay > 0us) {
-            testDelaySpin(std::chrono::duration_cast<std::chrono::duration<float>>(delay).count());
+        if (!ret.isOk()) {
+            state.SkipWithError(ret.description().c_str());
+            break;
         }
-        state.ResumeTiming();
+        if (delay > 0us) {
+            state.PauseTiming();
+            testDelaySpin(std::chrono::duration_cast<std::chrono::duration<float>>(delay).count());
+            state.ResumeTiming();
+        }
     }
 }