222 lines
6 KiB
C
222 lines
6 KiB
C
|
/*
|
||
|
* 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
|