123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221 |
- /*
- * Copyright (C) 2019 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 <list>
- #include <map>
- #include <sstream>
- #include <string>
- #include <android-base/unique_fd.h>
- #include <log/log.h>
- #include <sys/epoll.h>
- #include <utils/Trace.h>
- #include "utils.h"
- namespace aidl {
- namespace android {
- namespace hardware {
- namespace vibrator {
- using ::android::base::unique_fd;
- class HwApiBase {
- private:
- using NamesMap = std::map<const std::ios *, std::string>;
- class RecordInterface {
- public:
- virtual std::string toString(const NamesMap &names) = 0;
- virtual ~RecordInterface() {}
- };
- template <typename T>
- class Record : public RecordInterface {
- public:
- Record(const char *func, const T &value, const std::ios *stream)
- : mFunc(func), mValue(value), mStream(stream) {}
- std::string toString(const NamesMap &names) override;
- private:
- const char *mFunc;
- const T mValue;
- const std::ios *mStream;
- };
- using Records = std::list<std::unique_ptr<RecordInterface>>;
- static constexpr uint32_t RECORDS_SIZE = 32;
- public:
- HwApiBase();
- void debug(int fd);
- protected:
- void saveName(const std::string &name, const std::ios *stream);
- template <typename T>
- void open(const std::string &name, T *stream);
- bool has(const std::ios &stream);
- template <typename T>
- bool get(T *value, std::istream *stream);
- template <typename T>
- bool set(const T &value, std::ostream *stream);
- template <typename T>
- bool poll(const T &value, std::istream *stream, const int32_t timeout = -1);
- template <typename T>
- void record(const char *func, const T &value, const std::ios *stream);
- private:
- std::string mPathPrefix;
- NamesMap mNames;
- Records mRecords{RECORDS_SIZE};
- std::mutex mRecordsMutex;
- std::mutex mIoMutex;
- };
- #define HWAPI_RECORD(args...) HwApiBase::record(__FUNCTION__, ##args)
- template <typename T>
- void HwApiBase::open(const std::string &name, T *stream) {
- saveName(name, stream);
- utils::openNoCreate(mPathPrefix + name, stream);
- }
- template <typename T>
- bool HwApiBase::get(T *value, std::istream *stream) {
- ATRACE_NAME("HwApi::get");
- std::scoped_lock ioLock{mIoMutex};
- bool ret;
- stream->seekg(0);
- *stream >> *value;
- if (!(ret = !!*stream)) {
- ALOGE("Failed to read %s (%d): %s", mNames[stream].c_str(), errno, strerror(errno));
- }
- stream->clear();
- HWAPI_RECORD(*value, stream);
- return ret;
- }
- template <typename T>
- bool HwApiBase::set(const T &value, std::ostream *stream) {
- ATRACE_NAME("HwApi::set");
- using utils::operator<<;
- std::scoped_lock ioLock{mIoMutex};
- bool ret;
- *stream << value << std::endl;
- if (!(ret = !!*stream)) {
- ALOGE("Failed to write %s (%d): %s", mNames[stream].c_str(), errno, strerror(errno));
- stream->clear();
- }
- HWAPI_RECORD(value, stream);
- return ret;
- }
- template <typename T>
- bool HwApiBase::poll(const T &value, std::istream *stream, const int32_t timeoutMs) {
- ATRACE_NAME("HwApi::poll");
- auto path = mPathPrefix + mNames[stream];
- unique_fd fileFd{::open(path.c_str(), O_RDONLY)};
- unique_fd epollFd{epoll_create(1)};
- epoll_event event = {
- .events = EPOLLPRI | EPOLLET,
- };
- T actual;
- bool ret;
- int epollRet;
- if (timeoutMs < -1) {
- ALOGE("Invalid polling timeout!");
- return false;
- }
- if (epoll_ctl(epollFd, EPOLL_CTL_ADD, fileFd, &event)) {
- ALOGE("Failed to poll %s (%d): %s", mNames[stream].c_str(), errno, strerror(errno));
- return false;
- }
- while ((ret = get(&actual, stream)) && (actual != value)) {
- epollRet = epoll_wait(epollFd, &event, 1, timeoutMs);
- if (epollRet <= 0) {
- ALOGE("Polling error or timeout! (%d)", epollRet);
- return false;
- }
- }
- HWAPI_RECORD(value, stream);
- return ret;
- }
- template <typename T>
- void HwApiBase::record(const char *func, const T &value, const std::ios *stream) {
- std::lock_guard<std::mutex> lock(mRecordsMutex);
- mRecords.emplace_back(std::make_unique<Record<T>>(func, value, stream));
- mRecords.pop_front();
- }
- template <typename T>
- std::string HwApiBase::Record<T>::toString(const NamesMap &names) {
- using utils::operator<<;
- std::stringstream ret;
- ret << mFunc << " '" << names.at(mStream) << "' = '" << mValue << "'";
- return ret.str();
- }
- class HwCalBase {
- public:
- HwCalBase();
- void debug(int fd);
- protected:
- template <typename T>
- bool getProperty(const char *key, T *value, const T defval);
- template <typename T>
- bool getPersist(const char *key, T *value);
- private:
- std::string mPropertyPrefix;
- std::map<std::string, std::string> mCalData;
- };
- template <typename T>
- bool HwCalBase::getProperty(const char *key, T *outval, const T defval) {
- ATRACE_NAME("HwCal::getProperty");
- *outval = utils::getProperty(mPropertyPrefix + key, defval);
- return true;
- }
- template <typename T>
- bool HwCalBase::getPersist(const char *key, T *value) {
- ATRACE_NAME("HwCal::getPersist");
- auto it = mCalData.find(key);
- if (it == mCalData.end()) {
- ALOGE("Missing %s config!", key);
- return false;
- }
- std::stringstream stream{it->second};
- utils::unpack(stream, value);
- if (!stream || !stream.eof()) {
- ALOGE("Invalid %s config!", key);
- return false;
- }
- return true;
- }
- } // namespace vibrator
- } // namespace hardware
- } // namespace android
- } // namespace aidl
|