/* * Copyright (C) 2021 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include #include #include #include #include #include "Hardware.h" #include "StatsBase.h" #include "Vibrator.h" constexpr int32_t DURATION_BUCKET_WIDTH = 50; constexpr int32_t DURATION_50MS_BUCKET_COUNT = 20; constexpr int32_t DURATION_BUCKET_COUNT = DURATION_50MS_BUCKET_COUNT + 1; constexpr uint32_t MAX_TIME_MS = UINT16_MAX; #ifndef ARRAY_SIZE #define ARRAY_SIZE(x) (sizeof((x)) / sizeof((x)[0])) #endif #ifdef HAPTIC_TRACE static const char *kWaveformLookup[] = {"WAVEFORM_LONG_VIBRATION_EFFECT", "WAVEFORM_RESERVED_1", "WAVEFORM_CLICK", "WAVEFORM_SHORT_VIBRATION_EFFECT", "WAVEFORM_THUD", "WAVEFORM_SPIN", "WAVEFORM_QUICK_RISE", "WAVEFORM_SLOW_RISE", "WAVEFORM_QUICK_FALL", "WAVEFORM_LIGHT_TICK", "WAVEFORM_LOW_TICK", "WAVEFORM_RESERVED_MFG_1", "WAVEFORM_RESERVED_MFG_2", "WAVEFORM_RESERVED_MFG_3", "WAVEFORM_COMPOSE", "WAVEFORM_PWLE", "INVALID"}; static const char *kLatencyLookup[] = {"kWaveformEffectLatency", "kPrebakedEffectLatency", "kCompositionEffectLatency", "kPwleEffectLatency", "INVALID"}; static const char *kErrorLookup[] = {"kInitError", "kHwApiError", "kHwCalError", "kComposeFailError", "kAlsaFailError", "kAsyncFailError", "kBadTimeoutError", "kBadAmplitudeError", "kBadEffectError", "kBadEffectStrengthError", "kBadPrimitiveError", "kBadCompositeError", "kPwleConstructionFailError", "kUnsupportedOpError", "INVALID"}; const char *waveformToString(uint16_t index) { return kWaveformLookup[(index < ARRAY_SIZE(kWaveformLookup)) ? index : ARRAY_SIZE(kWaveformLookup) - 1]; } const char *latencyToString(uint16_t index) { return kLatencyLookup[(index < ARRAY_SIZE(kLatencyLookup)) ? index : ARRAY_SIZE(kLatencyLookup) - 1]; } const char *errorToString(uint16_t index) { return kErrorLookup[(index < ARRAY_SIZE(kErrorLookup)) ? index : ARRAY_SIZE(kErrorLookup) - 1]; } #define STATS_TRACE(...) \ ATRACE_NAME(__func__); \ ALOGD(__VA_ARGS__) #else #define STATS_TRACE(...) ATRACE_NAME(__func__) #define waveformToString(x) #define latencyToString(x) #define errorToString(x) #endif namespace aidl { namespace android { namespace hardware { namespace vibrator { enum EffectLatency : uint16_t { kWaveformEffectLatency = 0, kPrebakedEffectLatency, kCompositionEffectLatency, kPwleEffectLatency, kEffectLatencyCount }; enum VibratorError : uint16_t { kInitError = 0, kHwApiError, kHwCalError, kComposeFailError, kAlsaFailError, kAsyncFailError, kBadTimeoutError, kBadAmplitudeError, kBadEffectError, kBadEffectStrengthError, kBadPrimitiveError, kBadCompositeError, kPwleConstructionFailError, kUnsupportedOpError, kVibratorErrorCount }; class StatsApi : public Vibrator::StatsApi, private StatsBase { public: StatsApi() : StatsBase(std::string(std::getenv("STATS_INSTANCE"))), mCurrentLatencyIndex(kEffectLatencyCount) { mWaveformCounts = std::vector(WAVEFORM_MAX_INDEX, 0); mDurationCounts = std::vector(DURATION_BUCKET_COUNT, 0); mMinLatencies = std::vector(kEffectLatencyCount, 0); mMaxLatencies = std::vector(kEffectLatencyCount, 0); mLatencyTotals = std::vector(kEffectLatencyCount, 0); mLatencyCounts = std::vector(kEffectLatencyCount, 0); mErrorCounts = std::vector(kVibratorErrorCount, 0); } bool logPrimitive(uint16_t effectIndex) override { STATS_TRACE("logPrimitive(effectIndex: %s)", waveformToString(effectIndex)); if (effectIndex >= WAVEFORM_MAX_PHYSICAL_INDEX || effectIndex == WAVEFORM_LONG_VIBRATION_EFFECT_INDEX || effectIndex == WAVEFORM_SHORT_VIBRATION_EFFECT_INDEX) { ALOGE("Invalid waveform index for logging primitive: %d", effectIndex); return false; } { std::scoped_lock lock(mDataAccess); mWaveformCounts[effectIndex]++; } return true; } bool logWaveform(uint16_t effectIndex, int32_t duration) override { STATS_TRACE("logWaveform(effectIndex: %s, duration: %d)", waveformToString(effectIndex), duration); if (effectIndex != WAVEFORM_LONG_VIBRATION_EFFECT_INDEX && effectIndex != WAVEFORM_SHORT_VIBRATION_EFFECT_INDEX) { ALOGE("Invalid waveform index for logging waveform: %d", effectIndex); return false; } if (duration > MAX_TIME_MS || duration < 0) { ALOGE("Invalid waveform duration for logging waveform: %d", duration); return false; } { std::scoped_lock lock(mDataAccess); mWaveformCounts[effectIndex]++; if (duration < DURATION_BUCKET_WIDTH * DURATION_50MS_BUCKET_COUNT) { mDurationCounts[duration / DURATION_BUCKET_WIDTH]++; } else { mDurationCounts[DURATION_50MS_BUCKET_COUNT]++; } } return true; } bool logError(uint16_t errorIndex) override { STATS_TRACE("logError(errorIndex: %s)", errorToString(errorIndex)); if (errorIndex >= kVibratorErrorCount) { ALOGE("Invalid index for logging error: %d", errorIndex); return false; } { std::scoped_lock lock(mDataAccess); mErrorCounts[errorIndex]++; } return true; } bool logLatencyStart(uint16_t latencyIndex) override { STATS_TRACE("logLatencyStart(latencyIndex: %s)", latencyToString(latencyIndex)); if (latencyIndex >= kEffectLatencyCount) { ALOGE("Invalid index for measuring latency: %d", latencyIndex); return false; } mCurrentLatencyStart = std::chrono::steady_clock::now(); mCurrentLatencyIndex = latencyIndex; return true; } bool logLatencyEnd() override { STATS_TRACE("logLatencyEnd()"); if (mCurrentLatencyIndex >= kEffectLatencyCount) { return false; } int32_t latency = (std::chrono::duration_cast( std::chrono::steady_clock::now() - mCurrentLatencyStart)) .count(); { std::scoped_lock lock(mDataAccess); if (latency < mMinLatencies[mCurrentLatencyIndex] || mMinLatencies[mCurrentLatencyIndex] == 0) { mMinLatencies[mCurrentLatencyIndex] = latency; } if (latency > mMaxLatencies[mCurrentLatencyIndex]) { mMaxLatencies[mCurrentLatencyIndex] = latency; } mLatencyTotals[mCurrentLatencyIndex] += latency; mLatencyCounts[mCurrentLatencyIndex]++; } mCurrentLatencyIndex = kEffectLatencyCount; return true; } void debug(int fd) override { StatsBase::debug(fd); } private: uint16_t mCurrentLatencyIndex; std::chrono::time_point mCurrentLatencyStart; }; } // namespace vibrator } // namespace hardware } // namespace android } // namespace aidl