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