1 /*
2 * Copyright (C) 2019 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 #pragma once
17
18 #include <list>
19 #include <map>
20 #include <sstream>
21 #include <string>
22
23 #include <android-base/unique_fd.h>
24 #include <log/log.h>
25 #include <sys/epoll.h>
26 #include <utils/Trace.h>
27
28 #include "utils.h"
29
30 namespace aidl {
31 namespace android {
32 namespace hardware {
33 namespace vibrator {
34
35 using ::android::base::unique_fd;
36
37 class HwApiBase {
38 private:
39 using NamesMap = std::map<const std::ios *, std::string>;
40
41 class RecordInterface {
42 public:
43 virtual std::string toString(const NamesMap &names) = 0;
~RecordInterface()44 virtual ~RecordInterface() {}
45 };
46 template <typename T>
47 class Record : public RecordInterface {
48 public:
Record(const char * func,const T & value,const std::ios * stream)49 Record(const char *func, const T &value, const std::ios *stream)
50 : mFunc(func), mValue(value), mStream(stream) {}
51 std::string toString(const NamesMap &names) override;
52
53 private:
54 const char *mFunc;
55 const T mValue;
56 const std::ios *mStream;
57 };
58 using Records = std::list<std::unique_ptr<RecordInterface>>;
59
60 static constexpr uint32_t RECORDS_SIZE = 32;
61
62 public:
63 HwApiBase();
64 void debug(int fd);
65
66 protected:
67 void saveName(const std::string &name, const std::ios *stream);
68 template <typename T>
69 void open(const std::string &name, T *stream);
70 bool has(const std::ios &stream);
71 template <typename T>
72 bool get(T *value, std::istream *stream);
73 template <typename T>
74 bool getStr(T *value, std::istream *stream);
75 template <typename T>
76 bool set(const T &value, std::ostream *stream);
77 template <typename T>
78 bool poll(const T &value, std::istream *stream);
79 template <typename T>
80 bool pollStr(const T &value, std::istream *stream, const int32_t timeout = -1);
81 template <typename T>
82 void record(const char *func, const T &value, const std::ios *stream);
83
84 private:
85 std::string mPathPrefix;
86 NamesMap mNames;
87 Records mRecords{RECORDS_SIZE};
88 std::mutex mRecordsMutex;
89 std::mutex mIoMutex;
90 };
91
92 #define HWAPI_RECORD(args...) HwApiBase::record(__FUNCTION__, ##args)
93
94 template <typename T>
open(const std::string & name,T * stream)95 void HwApiBase::open(const std::string &name, T *stream) {
96 saveName(name, stream);
97 utils::openNoCreate(mPathPrefix + name, stream);
98 }
99
100 template <typename T>
get(T * value,std::istream * stream)101 bool HwApiBase::get(T *value, std::istream *stream) {
102 ATRACE_NAME("HwApi::get");
103 std::scoped_lock ioLock{mIoMutex};
104 bool ret;
105 stream->seekg(0);
106 *stream >> *value;
107 if (!(ret = !!*stream)) {
108 ALOGE("Failed to read %s (%d): %s", mNames[stream].c_str(), errno, strerror(errno));
109 }
110 stream->clear();
111 HWAPI_RECORD(*value, stream);
112 return ret;
113 }
114
115 template <typename T>
getStr(T * value,std::istream * stream)116 bool HwApiBase::getStr(T *value, std::istream *stream) {
117 ATRACE_NAME("HwApi::getStr");
118 std::scoped_lock ioLock{mIoMutex};
119 bool ret;
120 stream->seekg(0);
121 utils::unpack(*stream, value);
122 if (!(ret = !!*stream)) {
123 ALOGE("Failed to read %s (%d): %s", mNames[stream].c_str(), errno, strerror(errno));
124 }
125 if (!(ret = stream->eof())) {
126 ALOGE("Invalid %s !", mNames[stream].c_str());
127 }
128 stream->clear();
129 HWAPI_RECORD(*value, stream);
130 return ret;
131 }
132
133 template <typename T>
set(const T & value,std::ostream * stream)134 bool HwApiBase::set(const T &value, std::ostream *stream) {
135 ATRACE_NAME("HwApi::set");
136 using utils::operator<<;
137 std::scoped_lock ioLock{mIoMutex};
138 bool ret;
139 *stream << value << std::endl;
140 if (!(ret = !!*stream)) {
141 ALOGE("Failed to write %s (%d): %s", mNames[stream].c_str(), errno, strerror(errno));
142 stream->clear();
143 }
144 HWAPI_RECORD(value, stream);
145 return ret;
146 }
147
148 template <typename T>
poll(const T & value,std::istream * stream)149 bool HwApiBase::poll(const T &value, std::istream *stream) {
150 ATRACE_NAME("HwApi::poll");
151 auto path = mPathPrefix + mNames[stream];
152 unique_fd fileFd{::open(path.c_str(), O_RDONLY)};
153 unique_fd epollFd{epoll_create(1)};
154 epoll_event event = {
155 .events = EPOLLPRI | EPOLLET,
156 };
157 T actual;
158 bool ret;
159
160 if (epoll_ctl(epollFd, EPOLL_CTL_ADD, fileFd, &event)) {
161 ALOGE("Failed to poll %s (%d): %s", mNames[stream].c_str(), errno, strerror(errno));
162 return false;
163 }
164
165 while ((ret = get(&actual, stream)) && (actual != value)) {
166 epoll_wait(epollFd, &event, 1, -1);
167 }
168
169 HWAPI_RECORD(value, stream);
170 return ret;
171 }
172
173 template <typename T>
pollStr(const T & value,std::istream * stream,const int32_t timeoutMs)174 bool HwApiBase::pollStr(const T &value, std::istream *stream, const int32_t timeoutMs) {
175 ATRACE_NAME("HwApi::pollStr");
176 auto path = mPathPrefix + mNames[stream];
177 unique_fd fileFd{::open(path.c_str(), O_RDONLY)};
178 unique_fd epollFd{epoll_create(1)};
179 epoll_event event = {
180 .events = EPOLLPRI | EPOLLET,
181 };
182 T actual;
183 bool ret;
184 int epollRet;
185
186 if (timeoutMs < -1) {
187 ALOGE("Invalid polling timeout!");
188 return false;
189 }
190
191 if (epoll_ctl(epollFd, EPOLL_CTL_ADD, fileFd, &event)) {
192 ALOGE("Failed to poll string %s (%d): %s", mNames[stream].c_str(), errno, strerror(errno));
193 return false;
194 }
195
196 while ((ret = getStr(&actual, stream)) && (actual != value)) {
197 epollRet = epoll_wait(epollFd, &event, 1, timeoutMs);
198 if (epollRet <= 0) {
199 ALOGE("Polling error or timeout! (%d)", epollRet);
200 return false;
201 }
202 }
203
204 HWAPI_RECORD(value, stream);
205 return ret;
206 }
207
208 template <typename T>
record(const char * func,const T & value,const std::ios * stream)209 void HwApiBase::record(const char *func, const T &value, const std::ios *stream) {
210 std::lock_guard<std::mutex> lock(mRecordsMutex);
211 mRecords.emplace_back(std::make_unique<Record<T>>(func, value, stream));
212 mRecords.pop_front();
213 }
214
215 template <typename T>
toString(const NamesMap & names)216 std::string HwApiBase::Record<T>::toString(const NamesMap &names) {
217 using utils::operator<<;
218 std::stringstream ret;
219
220 ret << mFunc << " '" << names.at(mStream) << "' = '" << mValue << "'";
221
222 return ret.str();
223 }
224
225 class HwCalBase {
226 public:
227 HwCalBase();
228 void debug(int fd);
229
230 protected:
231 template <typename T>
232 bool getProperty(const char *key, T *value, const T defval);
233 template <typename T>
234 bool getPersist(const char *key, T *value);
235
236 private:
237 std::string mPropertyPrefix;
238 std::map<std::string, std::string> mCalData;
239 };
240
241 template <typename T>
getProperty(const char * key,T * outval,const T defval)242 bool HwCalBase::getProperty(const char *key, T *outval, const T defval) {
243 ATRACE_NAME("HwCal::getProperty");
244 *outval = utils::getProperty(mPropertyPrefix + key, defval);
245 return true;
246 }
247
248 template <typename T>
getPersist(const char * key,T * value)249 bool HwCalBase::getPersist(const char *key, T *value) {
250 ATRACE_NAME("HwCal::getPersist");
251 auto it = mCalData.find(key);
252 if (it == mCalData.end()) {
253 ALOGE("Missing %s config!", key);
254 return false;
255 }
256 std::stringstream stream{it->second};
257 utils::unpack(stream, value);
258 if (!stream || !stream.eof()) {
259 ALOGE("Invalid %s config!", key);
260 return false;
261 }
262 return true;
263 }
264
265 } // namespace vibrator
266 } // namespace hardware
267 } // namespace android
268 } // namespace aidl
269