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 #ifndef ANDROID_HARDWARE_VIBRATOR_HARDWARE_BASE_H
17 #define ANDROID_HARDWARE_VIBRATOR_HARDWARE_BASE_H
18
19 #include <android-base/unique_fd.h>
20 #include <log/log.h>
21 #include <sys/epoll.h>
22 #include <utils/Trace.h>
23
24 #include <list>
25 #include <map>
26 #include <sstream>
27 #include <string>
28
29 #include "utils.h"
30
31 namespace android {
32 namespace hardware {
33 namespace vibrator {
34 namespace common {
35 namespace implementation {
36
37 using base::unique_fd;
38
39 class HwApiBase {
40 private:
41 using NamesMap = std::map<const std::ios *, std::string>;
42
43 class RecordInterface {
44 public:
45 virtual std::string toString(const NamesMap &names) = 0;
~RecordInterface()46 virtual ~RecordInterface() {}
47 };
48 template <typename T>
49 class Record : public RecordInterface {
50 public:
Record(const char * func,const T & value,const std::ios * stream)51 Record(const char *func, const T &value, const std::ios *stream)
52 : mFunc(func), mValue(value), mStream(stream) {}
53 std::string toString(const NamesMap &names) override;
54
55 private:
56 const char *mFunc;
57 const T mValue;
58 const std::ios *mStream;
59 };
60 using Records = std::list<std::unique_ptr<RecordInterface>>;
61
62 static constexpr uint32_t RECORDS_SIZE = 32;
63
64 public:
65 HwApiBase();
66 void debug(int fd);
67
68 protected:
69 template <typename T>
70 void open(const std::string &name, T *stream);
71 template <typename T>
72 void openFull(const std::string &name, T *stream);
73 bool has(const std::ios &stream);
74 template <typename T>
75 bool get(T *value, std::istream *stream);
76 template <typename T>
77 bool set(const T &value, std::ostream *stream);
78 template <typename T>
79 bool poll(const T &value, std::istream *stream);
80 template <typename T>
81 void record(const char *func, const T &value, const std::ios *stream);
82
83 private:
84 std::string mPathPrefix;
85 NamesMap mNames;
86 Records mRecords{RECORDS_SIZE};
87 std::mutex mRecordsMutex;
88 };
89
90 #define HWAPI_RECORD(args...) HwApiBase::record(__FUNCTION__, ##args)
91
92 template <typename T>
open(const std::string & name,T * stream)93 void HwApiBase::open(const std::string &name, T *stream) {
94 mNames[stream] = name;
95 utils::openNoCreate(mPathPrefix + name, stream);
96 }
97
98 template <typename T>
openFull(const std::string & name,T * stream)99 void HwApiBase::openFull(const std::string &name, T *stream) {
100 mNames[stream] = name;
101 utils::openNoCreate(name, stream);
102 }
103
104 template <typename T>
get(T * value,std::istream * stream)105 bool HwApiBase::get(T *value, std::istream *stream) {
106 ATRACE_NAME("HwApi::get");
107 bool ret;
108 stream->seekg(0);
109 *stream >> *value;
110 if (!(ret = !!*stream)) {
111 ALOGE("Failed to read %s (%d): %s", mNames[stream].c_str(), errno, strerror(errno));
112 }
113 stream->clear();
114 HWAPI_RECORD(*value, stream);
115 return ret;
116 }
117
118 template <typename T>
set(const T & value,std::ostream * stream)119 bool HwApiBase::set(const T &value, std::ostream *stream) {
120 ATRACE_NAME("HwApi::set");
121 using utils::operator<<;
122 bool ret;
123 *stream << value << std::endl;
124 if (!(ret = !!*stream)) {
125 ALOGE("Failed to write %s (%d): %s", mNames[stream].c_str(), errno, strerror(errno));
126 stream->clear();
127 }
128 HWAPI_RECORD(value, stream);
129 return ret;
130 }
131
132 template <typename T>
poll(const T & value,std::istream * stream)133 bool HwApiBase::poll(const T &value, std::istream *stream) {
134 ATRACE_NAME("HwApi::poll");
135 auto path = mPathPrefix + mNames[stream];
136 unique_fd fileFd{::open(path.c_str(), O_RDONLY)};
137 unique_fd epollFd{epoll_create(1)};
138 epoll_event event = {
139 .events = EPOLLPRI | EPOLLET,
140 };
141 T actual;
142 bool ret;
143
144 if (epoll_ctl(epollFd, EPOLL_CTL_ADD, fileFd, &event)) {
145 ALOGE("Failed to poll %s (%d): %s", mNames[stream].c_str(), errno, strerror(errno));
146 return false;
147 }
148
149 while ((ret = get(&actual, stream)) && (actual != value)) {
150 epoll_wait(epollFd, &event, 1, -1);
151 }
152
153 HWAPI_RECORD(value, stream);
154 return ret;
155 }
156
157 template <typename T>
record(const char * func,const T & value,const std::ios * stream)158 void HwApiBase::record(const char *func, const T &value, const std::ios *stream) {
159 std::lock_guard<std::mutex> lock(mRecordsMutex);
160 mRecords.emplace_back(std::make_unique<Record<T>>(func, value, stream));
161 mRecords.pop_front();
162 }
163
164 template <typename T>
toString(const NamesMap & names)165 std::string HwApiBase::Record<T>::toString(const NamesMap &names) {
166 using utils::operator<<;
167 std::stringstream ret;
168
169 ret << mFunc << " '" << names.at(mStream) << "' = '" << mValue << "'";
170
171 return ret.str();
172 }
173
174 class HwCalBase {
175 public:
176 HwCalBase();
177 void debug(int fd);
178
179 protected:
180 template <typename T>
181 bool getProperty(const char *key, T *value, const T defval);
182 template <typename T>
183 bool getPersist(const char *key, T *value);
184
185 private:
186 std::string mPropertyPrefix;
187 std::map<std::string, std::string> mCalData;
188 };
189
190 template <typename T>
getProperty(const char * key,T * outval,const T defval)191 bool HwCalBase::getProperty(const char *key, T *outval, const T defval) {
192 ATRACE_NAME("HwCal::getProperty");
193 *outval = utils::getProperty(mPropertyPrefix + key, defval);
194 return true;
195 }
196
197 template <typename T>
getPersist(const char * key,T * value)198 bool HwCalBase::getPersist(const char *key, T *value) {
199 ATRACE_NAME("HwCal::getPersist");
200 auto it = mCalData.find(key);
201 if (it == mCalData.end()) {
202 ALOGE("Missing %s config!", key);
203 return false;
204 }
205 std::stringstream stream{it->second};
206 utils::unpack(stream, value);
207 if (!stream || !stream.eof()) {
208 ALOGE("Invalid %s config!", key);
209 return false;
210 }
211 return true;
212 }
213
214 } // namespace implementation
215 } // namespace common
216 } // namespace vibrator
217 } // namespace hardware
218 } // namespace android
219
220 #endif // ANDROID_HARDWARE_VIBRATOR_HARDWARE_BASE_H
221