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

Commit ba47cbe6 authored by Lais Andrade's avatar Lais Andrade Committed by Android (Google) Code Review
Browse files

Merge "Fix binder transaction errors on vibrator benchmark tests" into main

parents b6a752f9 59a5d543
Loading
Loading
Loading
Loading
+359 −131
Original line number Diff line number Diff line
@@ -20,6 +20,8 @@
#include <android/hardware/vibrator/BnVibratorCallback.h>
#include <android/hardware/vibrator/IVibrator.h>
#include <binder/IServiceManager.h>
#include <binder/ProcessState.h>
#include <future>

using ::android::enum_range;
using ::android::sp;
@@ -31,9 +33,8 @@ using ::benchmark::Fixture;
using ::benchmark::kMicrosecond;
using ::benchmark::State;
using ::benchmark::internal::Benchmark;
using ::std::chrono::duration;
using ::std::chrono::duration_cast;
using ::std::chrono::high_resolution_clock;

using namespace ::std::chrono_literals;

namespace Aidl = ::android::hardware::vibrator;
namespace V1_0 = ::android::hardware::vibrator::V1_0;
@@ -41,15 +42,29 @@ 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;

// Timeout to wait for vibration callback completion.
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 {
  public:
    void TearDown(State& /*state*/) override {
        if (!mVibrator) {
            return;
    void SetUp(State& /*state*/) override {
        android::ProcessState::self()->setThreadPoolMaxThreadCount(1);
        android::ProcessState::self()->startThreadPool();
    }

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

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

@@ -66,7 +81,19 @@ class BaseBench : public Fixture {
template <typename I>
class VibratorBench : public BaseBench<I> {
  public:
    void SetUp(State& /*state*/) override { this->mVibrator = I::getService(); }
    void SetUp(State& state) override {
        BaseBench<I>::SetUp(state);
        this->mVibrator = I::getService();
    }

  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;
@@ -118,16 +145,25 @@ class VibratorEffectsBench : public VibratorBench<I> {
        });

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

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

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

@@ -157,24 +193,38 @@ class VibratorEffectsBench : public VibratorBench<I> {
using VibratorBench_V1_0 = VibratorBench<V1_0::IVibrator>;

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

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

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

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

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

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

@@ -185,20 +235,23 @@ BENCHMARK_WRAPPER(VibratorBench_V1_0, 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");
        state.SkipWithMessage("amplitude control unavailable");
        return;
    }

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

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

    mVibrator->off();
});

using VibratorEffectsBench_V1_0 = VibratorEffectsBench<V1_0::IVibrator, V1_0::Effect>;
@@ -218,7 +271,15 @@ using VibratorEffectsBench_V1_2 =
BENCHMARK_WRAPPER(VibratorEffectsBench_V1_2, perform_1_2,
                  { performBench(&state, &V1_2::IVibrator::perform_1_2); });

using VibratorBench_V1_3 = VibratorBench<V1_3::IVibrator>;
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) {
@@ -227,18 +288,23 @@ BENCHMARK_WRAPPER(VibratorBench_V1_3, supportsExternalControl, {
});

BENCHMARK_WRAPPER(VibratorBench_V1_3, setExternalControl, {
    bool enable = true;

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

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

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

@@ -248,13 +314,13 @@ BENCHMARK_WRAPPER(VibratorBench_V1_3, supportsExternalAmplitudeControl, {
        return;
    }

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

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

    mVibrator->setExternalControl(false);
});

BENCHMARK_WRAPPER(VibratorBench_V1_3, setExternalAmplitude, {
@@ -265,7 +331,9 @@ BENCHMARK_WRAPPER(VibratorBench_V1_3, setExternalAmplitude, {
        return;
    }

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

    if (!mVibrator->supportsAmplitudeControl()) {
        state.SkipWithMessage("amplitude control unavailable");
@@ -273,10 +341,10 @@ BENCHMARK_WRAPPER(VibratorBench_V1_3, setExternalAmplitude, {
    }

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

    mVibrator->setExternalControl(false);
});

using VibratorEffectsBench_V1_3 = VibratorEffectsBench<V1_3::IVibrator, V1_3::Effect, V1_2::Effect>;
@@ -286,9 +354,42 @@ BENCHMARK_WRAPPER(VibratorEffectsBench_V1_3, perform_1_3,

class VibratorBench_Aidl : public BaseBench<Aidl::IVibrator> {
  public:
    void SetUp(State& /*state*/) override {
    void SetUp(State& state) override {
        BaseBench::SetUp(state);
        this->mVibrator = android::waitForVintfService<Aidl::IVibrator>();
    }

    void TearDown(State& state) override {
        BaseBench::TearDown(state);
        if (mVibrator) {
            mVibrator->setExternalControl(false);
        }
    }

  protected:
    int32_t hasCapabilities(int32_t capabilities) {
        int32_t deviceCapabilities = 0;
        this->mVibrator->getCapabilities(&deviceCapabilities);
        return (deviceCapabilities & capabilities) == capabilities;
    }

    bool shouldSkipWithError(State& state, const android::binder::Status&& status) {
        if (!status.isOk()) {
            state.SkipWithError(status.toString8().c_str());
            return true;
        }
        return false;
    }

    static void SlowBenchConfig(Benchmark* b) { b->Iterations(VIBRATION_ITERATIONS); }
};

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

class HalCallback : public Aidl::BnVibratorCallback {
@@ -296,30 +397,70 @@ class HalCallback : public Aidl::BnVibratorCallback {
    HalCallback() = default;
    ~HalCallback() = default;

    android::binder::Status onComplete() override { return android::binder::Status::ok(); }
};
    android::binder::Status onComplete() override {
        mPromise.set_value();
        return android::binder::Status::ok();
    }

BENCHMARK_WRAPPER(VibratorBench_Aidl, on, {
    int32_t capabilities = 0;
    mVibrator->getCapabilities(&capabilities);
    void waitForComplete() {
        // Wait until the HAL has finished processing previous vibration before starting a new one,
        // so the HAL state is consistent on each run and metrics are less noisy. Some of the newest
        // HAL implementations are waiting on previous vibration cleanup and might be significantly
        // slower, so make sure we measure vibrations on a clean slate.
        mPromise.get_future().wait_for(VIBRATION_CALLBACK_TIMEOUT);
    }

    int32_t ms = INT32_MAX;
    auto cb = (capabilities & Aidl::IVibrator::CAP_ON_CALLBACK) ? new HalCallback() : nullptr;
  private:
    std::promise<void> mPromise;
};

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

    for (auto _ : state) {
        state.ResumeTiming();
        mVibrator->on(ms, cb);
        auto cb = hasCapabilities(Aidl::IVibrator::CAP_ON_CALLBACK) ? new HalCallback() : nullptr;

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

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

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

    for (auto _ : state) {
        auto cb = hasCapabilities(Aidl::IVibrator::CAP_ON_CALLBACK) ? new HalCallback() : nullptr;

        // Setup
        state.PauseTiming();
        mVibrator->on(INT32_MAX, nullptr);
        if (shouldSkipWithError(state, mVibrator->on(ms, cb))) {
            return;
        }
        state.ResumeTiming();

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

        // Cleanup
        state.PauseTiming();
        if (cb) {
            cb->waitForComplete();
        }
        state.ResumeTiming();
        mVibrator->off();
    }
});

@@ -327,76 +468,102 @@ BENCHMARK_WRAPPER(VibratorBench_Aidl, getCapabilities, {
    int32_t capabilities = 0;

    for (auto _ : state) {
        mVibrator->getCapabilities(&capabilities);
        if (shouldSkipWithError(state, mVibrator->getCapabilities(&capabilities))) {
            return;
        }
    }
});

BENCHMARK_WRAPPER(VibratorBench_Aidl, setAmplitude, {
    int32_t capabilities = 0;
    mVibrator->getCapabilities(&capabilities);
    if ((capabilities & Aidl::IVibrator::CAP_AMPLITUDE_CONTROL) == 0) {
    auto ms = MAX_ON_DURATION_MS;
    float amplitude = 1.0f;

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

    float amplitude = 1.0f;
    mVibrator->on(INT32_MAX, nullptr);
    auto cb = hasCapabilities(Aidl::IVibrator::CAP_ON_CALLBACK) ? new HalCallback() : nullptr;
    if (shouldSkipWithError(state, mVibrator->on(ms, cb))) {
        return;
    }

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

    mVibrator->off();
    shouldSkipWithError(state, mVibrator->off());
    if (cb) {
        cb->waitForComplete();
    }
});

BENCHMARK_WRAPPER(VibratorBench_Aidl, setExternalControl, {
    int32_t capabilities = 0;
    mVibrator->getCapabilities(&capabilities);
    if ((capabilities & Aidl::IVibrator::CAP_EXTERNAL_CONTROL) == 0) {
    if (!hasCapabilities(Aidl::IVibrator::CAP_EXTERNAL_CONTROL)) {
        state.SkipWithMessage("external control unavailable");
        return;
    }

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

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

BENCHMARK_WRAPPER(VibratorBench_Aidl, setExternalAmplitude, {
    int32_t capabilities = 0;
    mVibrator->getCapabilities(&capabilities);
    if ((capabilities & Aidl::IVibrator::CAP_EXTERNAL_CONTROL) == 0 ||
        (capabilities & Aidl::IVibrator::CAP_EXTERNAL_AMPLITUDE_CONTROL) == 0) {
    auto externalControl = static_cast<int32_t>(Aidl::IVibrator::CAP_EXTERNAL_CONTROL);
    auto externalAmplitudeControl =
            static_cast<int32_t>(Aidl::IVibrator::CAP_EXTERNAL_AMPLITUDE_CONTROL);
    if (!hasCapabilities(externalControl | externalAmplitudeControl)) {
        state.SkipWithMessage("external amplitude control unavailable");
        return;
    }

    float amplitude = 1.0f;
    mVibrator->setExternalControl(true);
    if (shouldSkipWithError(state, mVibrator->setExternalControl(true))) {
        return;
    }

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

    mVibrator->setExternalControl(false);
});

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

    for (auto _ : state) {
        mVibrator->getSupportedEffects(&supportedEffects);
        if (shouldSkipWithError(state, mVibrator->getSupportedEffects(&supportedEffects))) {
            return;
        }
    }
});

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

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

    for (auto _ : state) {
        mVibrator->getSupportedAlwaysOnEffects(&supportedEffects);
        if (shouldSkipWithError(state, mVibrator->getSupportedAlwaysOnEffects(&supportedEffects))) {
            return;
        }
    }
});

@@ -404,7 +571,9 @@ BENCHMARK_WRAPPER(VibratorBench_Aidl, getSupportedPrimitives, {
    std::vector<Aidl::CompositePrimitive> supportedPrimitives;

    for (auto _ : state) {
        mVibrator->getSupportedPrimitives(&supportedPrimitives);
        if (shouldSkipWithError(state, mVibrator->getSupportedPrimitives(&supportedPrimitives))) {
            return;
        }
    }
});

@@ -427,12 +596,30 @@ class VibratorEffectsBench_Aidl : public VibratorBench_Aidl {
    auto getStrength(const State& state) const {
        return static_cast<Aidl::EffectStrength>(this->getOtherArg(state, 1));
    }

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

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

BENCHMARK_WRAPPER(VibratorEffectsBench_Aidl, alwaysOnEnable, {
    int32_t capabilities = 0;
    mVibrator->getCapabilities(&capabilities);
    if ((capabilities & Aidl::IVibrator::CAP_ALWAYS_ON_CONTROL) == 0) {
    if (!hasCapabilities(Aidl::IVibrator::CAP_ALWAYS_ON_CONTROL)) {
        state.SkipWithMessage("always on control unavailable");
        return;
    }
@@ -441,25 +628,28 @@ BENCHMARK_WRAPPER(VibratorEffectsBench_Aidl, alwaysOnEnable, {
    auto effect = getEffect(state);
    auto strength = getStrength(state);

    std::vector<Aidl::Effect> supported;
    mVibrator->getSupportedAlwaysOnEffects(&supported);
    if (std::find(supported.begin(), supported.end(), effect) == supported.end()) {
        state.SkipWithMessage("always on effects unavailable");
    if (!isAlwaysOnEffectSupported(effect)) {
        state.SkipWithMessage("always on effect unsupported");
        return;
    }

    for (auto _ : state) {
        state.ResumeTiming();
        mVibrator->alwaysOnEnable(id, effect, strength);
        // Test
        if (shouldSkipWithError(state, mVibrator->alwaysOnEnable(id, effect, strength))) {
            return;
        }

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

BENCHMARK_WRAPPER(VibratorEffectsBench_Aidl, alwaysOnDisable, {
    int32_t capabilities = 0;
    mVibrator->getCapabilities(&capabilities);
    if ((capabilities & Aidl::IVibrator::CAP_ALWAYS_ON_CONTROL) == 0) {
    if (!hasCapabilities(Aidl::IVibrator::CAP_ALWAYS_ON_CONTROL)) {
        state.SkipWithMessage("always on control unavailable");
        return;
    }
@@ -468,42 +658,55 @@ BENCHMARK_WRAPPER(VibratorEffectsBench_Aidl, alwaysOnDisable, {
    auto effect = getEffect(state);
    auto strength = getStrength(state);

    std::vector<Aidl::Effect> supported;
    mVibrator->getSupportedAlwaysOnEffects(&supported);
    if (std::find(supported.begin(), supported.end(), effect) == supported.end()) {
        state.SkipWithMessage("always on effects unavailable");
    if (!isAlwaysOnEffectSupported(effect)) {
        state.SkipWithMessage("always on effect unsupported");
        return;
    }

    for (auto _ : state) {
        // Setup
        state.PauseTiming();
        mVibrator->alwaysOnEnable(id, effect, strength);
        if (shouldSkipWithError(state, mVibrator->alwaysOnEnable(id, effect, strength))) {
            return;
        }
        state.ResumeTiming();
        mVibrator->alwaysOnDisable(id);

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

BENCHMARK_WRAPPER(VibratorEffectsBench_Aidl, perform, {
    int32_t capabilities = 0;
    mVibrator->getCapabilities(&capabilities);

BENCHMARK_WRAPPER(SlowVibratorEffectsBench_Aidl, perform, {
    auto effect = getEffect(state);
    auto strength = getStrength(state);
    auto cb = (capabilities & Aidl::IVibrator::CAP_PERFORM_CALLBACK) ? new HalCallback() : nullptr;
    int32_t lengthMs = 0;

    std::vector<Aidl::Effect> supported;
    mVibrator->getSupportedEffects(&supported);
    if (std::find(supported.begin(), supported.end(), effect) == supported.end()) {
        state.SkipWithMessage("effects unavailable");
    if (!isEffectSupported(effect)) {
        state.SkipWithMessage("effect unsupported");
        return;
    }

    int32_t lengthMs = 0;

    for (auto _ : state) {
        state.ResumeTiming();
        mVibrator->perform(effect, strength, cb, &lengthMs);
        auto cb = hasCapabilities(Aidl::IVibrator::CAP_PERFORM_CALLBACK) ? new HalCallback()
                                                                         : nullptr;

        // Test
        if (shouldSkipWithError(state, mVibrator->perform(effect, strength, cb, &lengthMs))) {
            return;
        }

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

@@ -520,13 +723,29 @@ class VibratorPrimitivesBench_Aidl : public VibratorBench_Aidl {
    auto getPrimitive(const State& state) const {
        return static_cast<Aidl::CompositePrimitive>(this->getOtherArg(state, 0));
    }

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

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

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

    for (auto _ : state) {
        mVibrator->getCompositionDelayMax(&ms);
        if (shouldSkipWithError(state, mVibrator->getCompositionDelayMax(&ms))) {
            return;
        }
    }
});

@@ -534,14 +753,14 @@ BENCHMARK_WRAPPER(VibratorBench_Aidl, getCompositionSizeMax, {
    int32_t size = 0;

    for (auto _ : state) {
        mVibrator->getCompositionSizeMax(&size);
        if (shouldSkipWithError(state, mVibrator->getCompositionSizeMax(&size))) {
            return;
        }
    }
});

BENCHMARK_WRAPPER(VibratorPrimitivesBench_Aidl, getPrimitiveDuration, {
    int32_t capabilities = 0;
    mVibrator->getCapabilities(&capabilities);
    if ((capabilities & Aidl::IVibrator::CAP_COMPOSE_EFFECTS) == 0) {
    if (!hasCapabilities(Aidl::IVibrator::CAP_COMPOSE_EFFECTS)) {
        state.SkipWithMessage("compose effects unavailable");
        return;
    }
@@ -549,22 +768,20 @@ BENCHMARK_WRAPPER(VibratorPrimitivesBench_Aidl, getPrimitiveDuration, {
    auto primitive = getPrimitive(state);
    int32_t ms = 0;

    std::vector<Aidl::CompositePrimitive> supported;
    mVibrator->getSupportedPrimitives(&supported);
    if (std::find(supported.begin(), supported.end(), primitive) == supported.end()) {
        state.SkipWithMessage("supported primitives unavailable");
    if (!isPrimitiveSupported(primitive)) {
        state.SkipWithMessage("primitive unsupported");
        return;
    }

    for (auto _ : state) {
        mVibrator->getPrimitiveDuration(primitive, &ms);
        if (shouldSkipWithError(state, mVibrator->getPrimitiveDuration(primitive, &ms))) {
            return;
        }
    }
});

BENCHMARK_WRAPPER(VibratorPrimitivesBench_Aidl, compose, {
    int32_t capabilities = 0;
    mVibrator->getCapabilities(&capabilities);
    if ((capabilities & Aidl::IVibrator::CAP_COMPOSE_EFFECTS) == 0) {
BENCHMARK_WRAPPER(SlowVibratorPrimitivesBench_Aidl, compose, {
    if (!hasCapabilities(Aidl::IVibrator::CAP_COMPOSE_EFFECTS)) {
        state.SkipWithMessage("compose effects unavailable");
        return;
    }
@@ -574,22 +791,33 @@ BENCHMARK_WRAPPER(VibratorPrimitivesBench_Aidl, compose, {
    effect.scale = 1.0f;
    effect.delayMs = 0;

    std::vector<Aidl::CompositePrimitive> supported;
    mVibrator->getSupportedPrimitives(&supported);
    if (std::find(supported.begin(), supported.end(), effect.primitive) == supported.end()) {
        state.SkipWithMessage("supported primitives unavailable");
    if (effect.primitive == Aidl::CompositePrimitive::NOOP) {
        state.SkipWithMessage("skipping primitive NOOP");
        return;
    }
    if (!isPrimitiveSupported(effect.primitive)) {
        state.SkipWithMessage("primitive unsupported");
        return;
    }

    auto cb = new HalCallback();
    std::vector<Aidl::CompositeEffect> effects;
    effects.push_back(effect);

    for (auto _ : state) {
        state.ResumeTiming();
        mVibrator->compose(effects, cb);
        auto cb = new HalCallback();

        // Test
        if (shouldSkipWithError(state, mVibrator->compose(effects, cb))) {
            return;
        }

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