Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6677c6f5 authored by Lais Andrade's avatar Lais Andrade
Browse files

Remove Vibrator HIDL HAL benchmarks

Android Q is now no longer supported for launching or upgrading
devices in Android V so the vibrator HIDL HAL no longer needs to be
supported by Android.

Fix: 402690180
Bug: 308452413
Test: VibratorHalIntegrationBenchmark
Flag: EXEMPT removing dependencies from Android.bp
Change-Id: Icfb9b7c115a7ce7dad7035187fce19cd63e9c967
parent eab72dff
Loading
Loading
Loading
Loading
+0 −7
Original line number Diff line number Diff line
@@ -25,19 +25,12 @@ package {

cc_benchmark {
    name: "VibratorHalIntegrationBenchmark",
    defaults: ["hidl_defaults"],
    srcs: [
        "benchmark.cpp",
    ],
    shared_libs: [
        "android.hardware.vibrator-V3-ndk",
        "android.hardware.vibrator@1.0",
        "android.hardware.vibrator@1.1",
        "android.hardware.vibrator@1.2",
        "android.hardware.vibrator@1.3",
        "libbinder_ndk",
        "libhardware",
        "libhidlbase",
        "libutils",
    ],
    test_suites: ["device-tests"],
+79 −371
Original line number Diff line number Diff line
@@ -21,12 +21,8 @@

#include <android/binder_manager.h>
#include <android/binder_process.h>
#include <android/hardware/vibrator/1.3/IVibrator.h>
#include <future>

using ::android::hardware::hidl_enum_range;
using ::android::hardware::Return;
using ::android::hardware::details::hidl_enum_values;
using ::benchmark::Counter;
using ::benchmark::Fixture;
using ::benchmark::kMicrosecond;
@@ -34,14 +30,9 @@ using ::benchmark::State;
using ::benchmark::internal::Benchmark;
using ::ndk::enum_range;

using namespace ::aidl::android::hardware::vibrator;
using namespace ::std::chrono_literals;

namespace Aidl = ::aidl::android::hardware::vibrator;
namespace V1_0 = ::android::hardware::vibrator::V1_0;
namespace V1_1 = ::android::hardware::vibrator::V1_1;
namespace V1_2 = ::android::hardware::vibrator::V1_2;
namespace V1_3 = ::android::hardware::vibrator::V1_3;

// Fixed number of iterations for benchmarks that trigger a vibration on the loop.
// They require slow cleanup to ensure a stable state on each run and less noisy metrics.
static constexpr auto VIBRATION_ITERATIONS = 500;
@@ -52,328 +43,32 @@ static constexpr auto VIBRATION_CALLBACK_TIMEOUT = 100ms;
// Max duration the vibrator can be turned on, in milliseconds.
static constexpr uint32_t MAX_ON_DURATION_MS = UINT16_MAX;

template <typename I>
class BaseBench : public Fixture {
class VibratorBench : public Fixture {
  public:
    void SetUp(State& /*state*/) override {
        ABinderProcess_setThreadPoolMaxThreadCount(1);
        ABinderProcess_startThreadPool();
        auto serviceName = std::string(IVibrator::descriptor) + "/default";
        this->mVibrator = IVibrator::fromBinder(
                ndk::SpAIBinder(AServiceManager_waitForService(serviceName.c_str())));
    }

    void TearDown(State& /*state*/) override {
        if (mVibrator) {
            mVibrator->off();
            mVibrator->setExternalControl(false);
        }
    }

    static void DefaultConfig(Benchmark* b) { b->Unit(kMicrosecond); }

    static void DefaultArgs(Benchmark* /*b*/) { /* none */
    }

  protected:
    auto getOtherArg(const State& state, std::size_t index) const { return state.range(index + 0); }

  protected:
    std::shared_ptr<I> mVibrator;
};

template <typename I>
class VibratorBench : public BaseBench<I> {
  public:
    void SetUp(State& state) override {
        BaseBench<I>::SetUp(state);
        auto service = I::getService();
        if (service) {
            this->mVibrator = std::shared_ptr<I>(service.release());
        } else {
            this->mVibrator = nullptr;
        }
    }

  protected:
    bool shouldSkipWithError(State& state, const android::hardware::Return<V1_0::Status>&& ret) {
        if (!ret.isOk()) {
            state.SkipWithError(ret.description());
            return true;
        }
        return false;
    }
};

enum class EmptyEnum : uint32_t;
template <>
inline constexpr std::array<EmptyEnum, 0> hidl_enum_values<EmptyEnum> = {};

template <typename T, typename U>
std::set<T> difference(const hidl_enum_range<T>& t, const hidl_enum_range<U>& u) {
    class Compare {
      public:
        bool operator()(const T& a, const U& b) { return a < static_cast<T>(b); }
        bool operator()(const U& a, const T& b) { return static_cast<T>(a) < b; }
    };
    std::set<T> ret;

    std::set_difference(t.begin(), t.end(), u.begin(), u.end(),
                        std::insert_iterator<decltype(ret)>(ret, ret.begin()), Compare());

    return ret;
}

template <typename I, typename E1, typename E2 = EmptyEnum>
class VibratorEffectsBench : public VibratorBench<I> {
  public:
    using Effect = E1;
    using EffectStrength = V1_0::EffectStrength;
    using Status = V1_0::Status;

  public:
    static void DefaultArgs(Benchmark* b) {
        b->ArgNames({"Effect", "Strength"});
        for (const auto& effect : difference(hidl_enum_range<E1>(), hidl_enum_range<E2>())) {
            for (const auto& strength : hidl_enum_range<EffectStrength>()) {
                b->Args({static_cast<long>(effect), static_cast<long>(strength)});
            }
        }
    }

    void performBench(State* state, Return<void> (I::*performApi)(Effect, EffectStrength,
                                                                  typename I::perform_cb)) {
        auto effect = getEffect(*state);
        auto strength = getStrength(*state);
        bool supported = true;

        (*this->mVibrator.*performApi)(effect, strength, [&](Status status, uint32_t /*lengthMs*/) {
            if (status == Status::UNSUPPORTED_OPERATION) {
                supported = false;
            }
        });

        if (!supported) {
            state->SkipWithMessage("effect unsupported");
            return;
        }

        for (auto _ : *state) {
            // Test
            auto ret = (*this->mVibrator.*performApi)(
                    effect, strength, [](Status /*status*/, uint32_t /*lengthMs*/) {});

            // Cleanup
            state->PauseTiming();
            if (!ret.isOk()) {
                state->SkipWithError(ret.description());
                return;
            }
            if (this->shouldSkipWithError(*state, this->mVibrator->off())) {
                return;
            }
            state->ResumeTiming();
        }
    }
    static void DefaultArgs(Benchmark* /*b*/) { /* none */ }

  protected:
    auto getEffect(const State& state) const {
        return static_cast<Effect>(this->getOtherArg(state, 0));
    }

    auto getStrength(const State& state) const {
        return static_cast<EffectStrength>(this->getOtherArg(state, 1));
    }
};

#define BENCHMARK_WRAPPER(fixt, test, code)           \
    BENCHMARK_DEFINE_F(fixt, test)                    \
    /* NOLINTNEXTLINE */                              \
    (State & state) {                                 \
        if (!mVibrator) {                             \
            state.SkipWithMessage("HAL unavailable"); \
            return;                                   \
        }                                             \
                                                      \
        code                                          \
    }                                                 \
    BENCHMARK_REGISTER_F(fixt, test)->Apply(fixt::DefaultConfig)->Apply(fixt::DefaultArgs)

using VibratorBench_V1_0 = VibratorBench<V1_0::IVibrator>;

BENCHMARK_WRAPPER(VibratorBench_V1_0, on, {
    auto ms = MAX_ON_DURATION_MS;

    for (auto _ : state) {
        // Test
        if (shouldSkipWithError(state, mVibrator->on(ms))) {
            return;
        }

        // Cleanup
        state.PauseTiming();
        if (shouldSkipWithError(state, mVibrator->off())) {
            return;
        }
        state.ResumeTiming();
    }
});

BENCHMARK_WRAPPER(VibratorBench_V1_0, off, {
    auto ms = MAX_ON_DURATION_MS;

    for (auto _ : state) {
        // Setup
        state.PauseTiming();
        if (shouldSkipWithError(state, mVibrator->on(ms))) {
            return;
        }
        state.ResumeTiming();

        // Test
        if (shouldSkipWithError(state, mVibrator->off())) {
            return;
        }
    }
});

BENCHMARK_WRAPPER(VibratorBench_V1_0, supportsAmplitudeControl, {
    for (auto _ : state) {
        mVibrator->supportsAmplitudeControl();
    }
});

BENCHMARK_WRAPPER(VibratorBench_V1_0, setAmplitude, {
    auto ms = MAX_ON_DURATION_MS;
    uint8_t amplitude = UINT8_MAX;

    if (!mVibrator->supportsAmplitudeControl()) {
        state.SkipWithMessage("amplitude control unavailable");
        return;
    }

    if (shouldSkipWithError(state, mVibrator->on(ms))) {
        return;
    }

    for (auto _ : state) {
        if (shouldSkipWithError(state, mVibrator->setAmplitude(amplitude))) {
            return;
        }
    }
});

using VibratorEffectsBench_V1_0 = VibratorEffectsBench<V1_0::IVibrator, V1_0::Effect>;

BENCHMARK_WRAPPER(VibratorEffectsBench_V1_0, perform,
                  { performBench(&state, &V1_0::IVibrator::perform); });

using VibratorEffectsBench_V1_1 =
        VibratorEffectsBench<V1_1::IVibrator, V1_1::Effect_1_1, V1_0::Effect>;

BENCHMARK_WRAPPER(VibratorEffectsBench_V1_1, perform_1_1,
                  { performBench(&state, &V1_1::IVibrator::perform_1_1); });

using VibratorEffectsBench_V1_2 =
        VibratorEffectsBench<V1_2::IVibrator, V1_2::Effect, V1_1::Effect_1_1>;

BENCHMARK_WRAPPER(VibratorEffectsBench_V1_2, perform_1_2,
                  { performBench(&state, &V1_2::IVibrator::perform_1_2); });

class VibratorBench_V1_3 : public VibratorBench<V1_3::IVibrator> {
  public:
    void TearDown(State& state) override {
        VibratorBench::TearDown(state);
        if (mVibrator) {
            mVibrator->setExternalControl(false);
        }
    }
};

BENCHMARK_WRAPPER(VibratorBench_V1_3, supportsExternalControl, {
    for (auto _ : state) {
        mVibrator->supportsExternalControl();
    }
});

BENCHMARK_WRAPPER(VibratorBench_V1_3, setExternalControl, {
    if (!mVibrator->supportsExternalControl()) {
        state.SkipWithMessage("external control unavailable");
        return;
    }

    for (auto _ : state) {
        // Test
        if (shouldSkipWithError(state, mVibrator->setExternalControl(true))) {
            return;
        }

        // Cleanup
        state.PauseTiming();
        if (shouldSkipWithError(state, mVibrator->setExternalControl(false))) {
            return;
        }
        state.ResumeTiming();
    }
});

BENCHMARK_WRAPPER(VibratorBench_V1_3, supportsExternalAmplitudeControl, {
    if (!mVibrator->supportsExternalControl()) {
        state.SkipWithMessage("external control unavailable");
        return;
    }

    if (shouldSkipWithError(state, mVibrator->setExternalControl(true))) {
        return;
    }

    for (auto _ : state) {
        mVibrator->supportsAmplitudeControl();
    }
});

BENCHMARK_WRAPPER(VibratorBench_V1_3, setExternalAmplitude, {
    uint8_t amplitude = UINT8_MAX;

    if (!mVibrator->supportsExternalControl()) {
        state.SkipWithMessage("external control unavailable");
        return;
    }

    if (shouldSkipWithError(state, mVibrator->setExternalControl(true))) {
        return;
    }

    if (!mVibrator->supportsAmplitudeControl()) {
        state.SkipWithMessage("amplitude control unavailable");
        return;
    }

    for (auto _ : state) {
        if (shouldSkipWithError(state, mVibrator->setAmplitude(amplitude))) {
            return;
        }
    }
});

using VibratorEffectsBench_V1_3 = VibratorEffectsBench<V1_3::IVibrator, V1_3::Effect, V1_2::Effect>;

BENCHMARK_WRAPPER(VibratorEffectsBench_V1_3, perform_1_3,
                  { performBench(&state, &V1_3::IVibrator::perform_1_3); });

class VibratorBench_Aidl : public BaseBench<Aidl::IVibrator> {
  public:
    void SetUp(State& state) override {
        BaseBench::SetUp(state);
        auto serviceName = std::string(Aidl::IVibrator::descriptor) + "/default";
        this->mVibrator = Aidl::IVibrator::fromBinder(
                ndk::SpAIBinder(AServiceManager_waitForService(serviceName.c_str())));
    }
    std::shared_ptr<IVibrator> mVibrator;

    void TearDown(State& state) override {
        BaseBench::TearDown(state);
        if (mVibrator) {
            mVibrator->setExternalControl(false);
        }
    }
    auto getOtherArg(const State& state, std::size_t index) const { return state.range(index + 0); }

  protected:
    int32_t hasCapabilities(int32_t capabilities) {
        int32_t deviceCapabilities = 0;
        this->mVibrator->getCapabilities(&deviceCapabilities);
@@ -401,15 +96,15 @@ class VibratorBench_Aidl : public BaseBench<Aidl::IVibrator> {
    static void SlowBenchConfig(Benchmark* b) { b->Iterations(VIBRATION_ITERATIONS); }
};

class SlowVibratorBench_Aidl : public VibratorBench_Aidl {
class SlowVibratorBench : public VibratorBench {
  public:
    static void DefaultConfig(Benchmark* b) {
        VibratorBench_Aidl::DefaultConfig(b);
        VibratorBench::DefaultConfig(b);
        SlowBenchConfig(b);
    }
};

class HalCallback : public Aidl::BnVibratorCallback {
class HalCallback : public BnVibratorCallback {
  public:
    HalCallback() = default;
    ~HalCallback() = default;
@@ -425,11 +120,24 @@ class HalCallback : public Aidl::BnVibratorCallback {
    std::promise<void> mPromise;
};

BENCHMARK_WRAPPER(SlowVibratorBench_Aidl, on, {
#define BENCHMARK_WRAPPER(fixt, test, code)           \
    BENCHMARK_DEFINE_F(fixt, test)                    \
    /* NOLINTNEXTLINE */                              \
    (State & state) {                                 \
        if (!mVibrator) {                             \
            state.SkipWithMessage("HAL unavailable"); \
            return;                                   \
        }                                             \
                                                      \
        code                                          \
    }                                                 \
    BENCHMARK_REGISTER_F(fixt, test)->Apply(fixt::DefaultConfig)->Apply(fixt::DefaultArgs)

BENCHMARK_WRAPPER(SlowVibratorBench, on, {
    auto ms = MAX_ON_DURATION_MS;

    for (auto _ : state) {
        auto cb = hasCapabilities(Aidl::IVibrator::CAP_ON_CALLBACK)
        auto cb = hasCapabilities(IVibrator::CAP_ON_CALLBACK)
                          ? ndk::SharedRefBase::make<HalCallback>()
                          : nullptr;
        // Grab the future before callback promise is destroyed by the HAL.
@@ -450,11 +158,11 @@ BENCHMARK_WRAPPER(SlowVibratorBench_Aidl, on, {
    }
});

BENCHMARK_WRAPPER(SlowVibratorBench_Aidl, off, {
BENCHMARK_WRAPPER(SlowVibratorBench, off, {
    auto ms = MAX_ON_DURATION_MS;

    for (auto _ : state) {
        auto cb = hasCapabilities(Aidl::IVibrator::CAP_ON_CALLBACK)
        auto cb = hasCapabilities(IVibrator::CAP_ON_CALLBACK)
                          ? ndk::SharedRefBase::make<HalCallback>()
                          : nullptr;
        // Grab the future before callback promise is destroyed by the HAL.
@@ -479,7 +187,7 @@ BENCHMARK_WRAPPER(SlowVibratorBench_Aidl, off, {
    }
});

BENCHMARK_WRAPPER(VibratorBench_Aidl, getCapabilities, {
BENCHMARK_WRAPPER(VibratorBench, getCapabilities, {
    int32_t capabilities = 0;

    for (auto _ : state) {
@@ -489,16 +197,16 @@ BENCHMARK_WRAPPER(VibratorBench_Aidl, getCapabilities, {
    }
});

BENCHMARK_WRAPPER(VibratorBench_Aidl, setAmplitude, {
BENCHMARK_WRAPPER(VibratorBench, setAmplitude, {
    auto ms = MAX_ON_DURATION_MS;
    float amplitude = 1.0f;

    if (!hasCapabilities(Aidl::IVibrator::CAP_AMPLITUDE_CONTROL)) {
    if (!hasCapabilities(IVibrator::CAP_AMPLITUDE_CONTROL)) {
        state.SkipWithMessage("amplitude control unavailable");
        return;
    }

    auto cb = hasCapabilities(Aidl::IVibrator::CAP_ON_CALLBACK)
    auto cb = hasCapabilities(IVibrator::CAP_ON_CALLBACK)
                      ? ndk::SharedRefBase::make<HalCallback>()
                      : nullptr;
    if (shouldSkipWithError(state, mVibrator->on(ms, cb))) {
@@ -512,8 +220,8 @@ BENCHMARK_WRAPPER(VibratorBench_Aidl, setAmplitude, {
    }
});

BENCHMARK_WRAPPER(VibratorBench_Aidl, setExternalControl, {
    if (!hasCapabilities(Aidl::IVibrator::CAP_EXTERNAL_CONTROL)) {
BENCHMARK_WRAPPER(VibratorBench, setExternalControl, {
    if (!hasCapabilities(IVibrator::CAP_EXTERNAL_CONTROL)) {
        state.SkipWithMessage("external control unavailable");
        return;
    }
@@ -533,10 +241,10 @@ BENCHMARK_WRAPPER(VibratorBench_Aidl, setExternalControl, {
    }
});

BENCHMARK_WRAPPER(VibratorBench_Aidl, setExternalAmplitude, {
    auto externalControl = static_cast<int32_t>(Aidl::IVibrator::CAP_EXTERNAL_CONTROL);
BENCHMARK_WRAPPER(VibratorBench, setExternalAmplitude, {
    auto externalControl = static_cast<int32_t>(IVibrator::CAP_EXTERNAL_CONTROL);
    auto externalAmplitudeControl =
            static_cast<int32_t>(Aidl::IVibrator::CAP_EXTERNAL_AMPLITUDE_CONTROL);
            static_cast<int32_t>(IVibrator::CAP_EXTERNAL_AMPLITUDE_CONTROL);
    if (!hasCapabilities(externalControl | externalAmplitudeControl)) {
        state.SkipWithMessage("external amplitude control unavailable");
        return;
@@ -554,8 +262,8 @@ BENCHMARK_WRAPPER(VibratorBench_Aidl, setExternalAmplitude, {
    }
});

BENCHMARK_WRAPPER(VibratorBench_Aidl, getSupportedEffects, {
    std::vector<Aidl::Effect> supportedEffects;
BENCHMARK_WRAPPER(VibratorBench, getSupportedEffects, {
    std::vector<Effect> supportedEffects;

    for (auto _ : state) {
        if (shouldSkipWithError(state, mVibrator->getSupportedEffects(&supportedEffects))) {
@@ -564,13 +272,13 @@ BENCHMARK_WRAPPER(VibratorBench_Aidl, getSupportedEffects, {
    }
});

BENCHMARK_WRAPPER(VibratorBench_Aidl, getSupportedAlwaysOnEffects, {
    if (!hasCapabilities(Aidl::IVibrator::CAP_ALWAYS_ON_CONTROL)) {
BENCHMARK_WRAPPER(VibratorBench, getSupportedAlwaysOnEffects, {
    if (!hasCapabilities(IVibrator::CAP_ALWAYS_ON_CONTROL)) {
        state.SkipWithMessage("always on control unavailable");
        return;
    }

    std::vector<Aidl::Effect> supportedEffects;
    std::vector<Effect> supportedEffects;

    for (auto _ : state) {
        if (shouldSkipWithError(state, mVibrator->getSupportedAlwaysOnEffects(&supportedEffects))) {
@@ -579,8 +287,8 @@ BENCHMARK_WRAPPER(VibratorBench_Aidl, getSupportedAlwaysOnEffects, {
    }
});

BENCHMARK_WRAPPER(VibratorBench_Aidl, getSupportedPrimitives, {
    std::vector<Aidl::CompositePrimitive> supportedPrimitives;
BENCHMARK_WRAPPER(VibratorBench, getSupportedPrimitives, {
    std::vector<CompositePrimitive> supportedPrimitives;

    for (auto _ : state) {
        if (shouldSkipWithError(state, mVibrator->getSupportedPrimitives(&supportedPrimitives))) {
@@ -589,12 +297,12 @@ BENCHMARK_WRAPPER(VibratorBench_Aidl, getSupportedPrimitives, {
    }
});

class VibratorEffectsBench_Aidl : public VibratorBench_Aidl {
class EffectsVibratorBench : public VibratorBench {
  public:
    static void DefaultArgs(Benchmark* b) {
        b->ArgNames({"Effect", "Strength"});
        for (const auto& effect : enum_range<Aidl::Effect>()) {
            for (const auto& strength : enum_range<Aidl::EffectStrength>()) {
        for (const auto& effect : enum_range<Effect>()) {
            for (const auto& strength : enum_range<EffectStrength>()) {
                b->Args({static_cast<long>(effect), static_cast<long>(strength)});
            }
        }
@@ -602,36 +310,36 @@ class VibratorEffectsBench_Aidl : public VibratorBench_Aidl {

  protected:
    auto getEffect(const State& state) const {
        return static_cast<Aidl::Effect>(this->getOtherArg(state, 0));
        return static_cast<Effect>(this->getOtherArg(state, 0));
    }

    auto getStrength(const State& state) const {
        return static_cast<Aidl::EffectStrength>(this->getOtherArg(state, 1));
        return static_cast<EffectStrength>(this->getOtherArg(state, 1));
    }

    bool isEffectSupported(const Aidl::Effect& effect) {
        std::vector<Aidl::Effect> supported;
    bool isEffectSupported(const Effect& effect) {
        std::vector<Effect> supported;
        mVibrator->getSupportedEffects(&supported);
        return std::find(supported.begin(), supported.end(), effect) != supported.end();
    }

    bool isAlwaysOnEffectSupported(const Aidl::Effect& effect) {
        std::vector<Aidl::Effect> supported;
    bool isAlwaysOnEffectSupported(const Effect& effect) {
        std::vector<Effect> supported;
        mVibrator->getSupportedAlwaysOnEffects(&supported);
        return std::find(supported.begin(), supported.end(), effect) != supported.end();
    }
};

class SlowVibratorEffectsBench_Aidl : public VibratorEffectsBench_Aidl {
class SlowEffectsVibratorBench : public EffectsVibratorBench {
  public:
    static void DefaultConfig(Benchmark* b) {
        VibratorEffectsBench_Aidl::DefaultConfig(b);
        EffectsVibratorBench::DefaultConfig(b);
        SlowBenchConfig(b);
    }
};

BENCHMARK_WRAPPER(VibratorEffectsBench_Aidl, alwaysOnEnable, {
    if (!hasCapabilities(Aidl::IVibrator::CAP_ALWAYS_ON_CONTROL)) {
BENCHMARK_WRAPPER(EffectsVibratorBench, alwaysOnEnable, {
    if (!hasCapabilities(IVibrator::CAP_ALWAYS_ON_CONTROL)) {
        state.SkipWithMessage("always on control unavailable");
        return;
    }
@@ -660,8 +368,8 @@ BENCHMARK_WRAPPER(VibratorEffectsBench_Aidl, alwaysOnEnable, {
    }
});

BENCHMARK_WRAPPER(VibratorEffectsBench_Aidl, alwaysOnDisable, {
    if (!hasCapabilities(Aidl::IVibrator::CAP_ALWAYS_ON_CONTROL)) {
BENCHMARK_WRAPPER(EffectsVibratorBench, alwaysOnDisable, {
    if (!hasCapabilities(IVibrator::CAP_ALWAYS_ON_CONTROL)) {
        state.SkipWithMessage("always on control unavailable");
        return;
    }
@@ -690,7 +398,7 @@ BENCHMARK_WRAPPER(VibratorEffectsBench_Aidl, alwaysOnDisable, {
    }
});

BENCHMARK_WRAPPER(SlowVibratorEffectsBench_Aidl, perform, {
BENCHMARK_WRAPPER(SlowEffectsVibratorBench, perform, {
    auto effect = getEffect(state);
    auto strength = getStrength(state);

@@ -702,7 +410,7 @@ BENCHMARK_WRAPPER(SlowVibratorEffectsBench_Aidl, perform, {
    int32_t lengthMs = 0;

    for (auto _ : state) {
        auto cb = hasCapabilities(Aidl::IVibrator::CAP_PERFORM_CALLBACK)
        auto cb = hasCapabilities(IVibrator::CAP_PERFORM_CALLBACK)
                          ? ndk::SharedRefBase::make<HalCallback>()
                          : nullptr;
        // Grab the future before callback promise is destroyed by the HAL.
@@ -723,36 +431,36 @@ BENCHMARK_WRAPPER(SlowVibratorEffectsBench_Aidl, perform, {
    }
});

class VibratorPrimitivesBench_Aidl : public VibratorBench_Aidl {
class PrimitivesVibratorBench : public VibratorBench {
  public:
    static void DefaultArgs(Benchmark* b) {
        b->ArgNames({"Primitive"});
        for (const auto& primitive : enum_range<Aidl::CompositePrimitive>()) {
        for (const auto& primitive : enum_range<CompositePrimitive>()) {
            b->Args({static_cast<long>(primitive)});
        }
    }

  protected:
    auto getPrimitive(const State& state) const {
        return static_cast<Aidl::CompositePrimitive>(this->getOtherArg(state, 0));
        return static_cast<CompositePrimitive>(this->getOtherArg(state, 0));
    }

    bool isPrimitiveSupported(const Aidl::CompositePrimitive& primitive) {
        std::vector<Aidl::CompositePrimitive> supported;
    bool isPrimitiveSupported(const CompositePrimitive& primitive) {
        std::vector<CompositePrimitive> supported;
        mVibrator->getSupportedPrimitives(&supported);
        return std::find(supported.begin(), supported.end(), primitive) != supported.end();
    }
};

class SlowVibratorPrimitivesBench_Aidl : public VibratorPrimitivesBench_Aidl {
class SlowPrimitivesVibratorBench : public PrimitivesVibratorBench {
  public:
    static void DefaultConfig(Benchmark* b) {
        VibratorPrimitivesBench_Aidl::DefaultConfig(b);
      PrimitivesVibratorBench::DefaultConfig(b);
      SlowBenchConfig(b);
    }
};

BENCHMARK_WRAPPER(VibratorBench_Aidl, getCompositionDelayMax, {
BENCHMARK_WRAPPER(PrimitivesVibratorBench, getCompositionDelayMax, {
    int32_t ms = 0;

    for (auto _ : state) {
@@ -762,7 +470,7 @@ BENCHMARK_WRAPPER(VibratorBench_Aidl, getCompositionDelayMax, {
    }
});

BENCHMARK_WRAPPER(VibratorBench_Aidl, getCompositionSizeMax, {
BENCHMARK_WRAPPER(PrimitivesVibratorBench, getCompositionSizeMax, {
    int32_t size = 0;

    for (auto _ : state) {
@@ -772,8 +480,8 @@ BENCHMARK_WRAPPER(VibratorBench_Aidl, getCompositionSizeMax, {
    }
});

BENCHMARK_WRAPPER(VibratorPrimitivesBench_Aidl, getPrimitiveDuration, {
    if (!hasCapabilities(Aidl::IVibrator::CAP_COMPOSE_EFFECTS)) {
BENCHMARK_WRAPPER(PrimitivesVibratorBench, getPrimitiveDuration, {
    if (!hasCapabilities(IVibrator::CAP_COMPOSE_EFFECTS)) {
        state.SkipWithMessage("compose effects unavailable");
        return;
    }
@@ -793,18 +501,18 @@ BENCHMARK_WRAPPER(VibratorPrimitivesBench_Aidl, getPrimitiveDuration, {
    }
});

BENCHMARK_WRAPPER(SlowVibratorPrimitivesBench_Aidl, compose, {
    if (!hasCapabilities(Aidl::IVibrator::CAP_COMPOSE_EFFECTS)) {
BENCHMARK_WRAPPER(SlowPrimitivesVibratorBench, compose, {
    if (!hasCapabilities(IVibrator::CAP_COMPOSE_EFFECTS)) {
        state.SkipWithMessage("compose effects unavailable");
        return;
    }

    Aidl::CompositeEffect effect;
    CompositeEffect effect;
    effect.primitive = getPrimitive(state);
    effect.scale = 1.0f;
    effect.delayMs = 0;

    if (effect.primitive == Aidl::CompositePrimitive::NOOP) {
    if (effect.primitive == CompositePrimitive::NOOP) {
        state.SkipWithMessage("skipping primitive NOOP");
        return;
    }
@@ -813,7 +521,7 @@ BENCHMARK_WRAPPER(SlowVibratorPrimitivesBench_Aidl, compose, {
        return;
    }

    std::vector<Aidl::CompositeEffect> effects;
    std::vector<CompositeEffect> effects;
    effects.push_back(effect);

    for (auto _ : state) {