• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <android-base/stringprintf.h>
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 <chrono>
25 #include <list>
26 #include <map>
27 #include <sstream>
28 #include <string>
29 
30 #include "utils.h"
31 
32 namespace aidl {
33 namespace android {
34 namespace hardware {
35 namespace vibrator {
36 
37 using ::android::base::StringPrintf;
38 using ::android::base::unique_fd;
39 
40 class HwApiBase {
41   private:
42     using NamesMap = std::map<const std::ios *, std::string>;
43 
44     class RecordInterface {
45       public:
46         virtual std::string toString(const NamesMap &names) = 0;
~RecordInterface()47         virtual ~RecordInterface() {}
48     };
49     template <typename T>
50     class Record : public RecordInterface {
51       public:
Record(const char * func,const T & value,const std::ios * stream)52         Record(const char *func, const T &value, const std::ios *stream)
53             : mFunc(func),
54               mValue(value),
55               mStream(stream),
56               mTp(std::chrono::system_clock::system_clock::now()) {}
57         std::string toString(const NamesMap &names) override;
58 
59       private:
60         const char *mFunc;
61         const T mValue;
62         const std::ios *mStream;
63         const std::chrono::system_clock::time_point mTp;
64     };
65     using Records = std::list<std::unique_ptr<RecordInterface>>;
66 
67     static constexpr uint32_t RECORDS_SIZE = 2048;
68 
69   public:
70     HwApiBase();
71     void debug(int fd);
72 
73   protected:
updatePathPrefix(const std::string & prefix)74     void updatePathPrefix(const std::string &prefix) {
75         ALOGI("Update HWAPI path prefix to %s", prefix.c_str());
76         mPathPrefix = prefix;
77     }
78     void saveName(const std::string &name, const std::ios *stream);
79     template <typename T>
80     void open(const std::string &name, T *stream);
81     bool has(const std::ios &stream);
82     template <typename T>
83     bool get(T *value, std::istream *stream);
84     template <typename T>
85     bool set(const T &value, std::ostream *stream);
86     template <typename T>
87     bool poll(const T &value, std::istream *stream, const int32_t timeout = -1);
88     template <typename T>
89     void record(const char *func, const T &value, const std::ios *stream);
90 
91   private:
92     std::string mPathPrefix;
93     NamesMap mNames;
94     Records mRecords{RECORDS_SIZE};
95     std::mutex mRecordsMutex;
96     std::mutex mIoMutex;
97 };
98 
99 #define HWAPI_RECORD(args...) HwApiBase::record(__FUNCTION__, ##args)
100 
101 template <typename T>
open(const std::string & name,T * stream)102 void HwApiBase::open(const std::string &name, T *stream) {
103     saveName(name, stream);
104     utils::openNoCreate(mPathPrefix + name, stream);
105 }
106 
107 template <typename T>
get(T * value,std::istream * stream)108 bool HwApiBase::get(T *value, std::istream *stream) {
109     ATRACE_NAME("HwApi::get");
110     std::scoped_lock ioLock{mIoMutex};
111     bool ret;
112     stream->seekg(0);
113     *stream >> *value;
114     if (!(ret = !!*stream)) {
115         ALOGE("Failed to read %s (%d): %s", mNames[stream].c_str(), errno, strerror(errno));
116     }
117     stream->clear();
118     HWAPI_RECORD(*value, stream);
119     return ret;
120 }
121 
122 template <typename T>
set(const T & value,std::ostream * stream)123 bool HwApiBase::set(const T &value, std::ostream *stream) {
124     ATRACE_NAME("HwApi::set");
125     using utils::operator<<;
126     std::scoped_lock ioLock{mIoMutex};
127     bool ret;
128     *stream << value << std::endl;
129     if (!(ret = !!*stream)) {
130         ALOGE("Failed to write %s (%d): %s", mNames[stream].c_str(), errno, strerror(errno));
131         stream->clear();
132     }
133     HWAPI_RECORD(value, stream);
134     return ret;
135 }
136 
137 template <typename T>
poll(const T & value,std::istream * stream,const int32_t timeoutMs)138 bool HwApiBase::poll(const T &value, std::istream *stream, const int32_t timeoutMs) {
139     ATRACE_NAME(StringPrintf("HwApi::poll %s==%s", mNames[stream].c_str(),
140                              std::to_string(value).c_str())
141                         .c_str());
142     auto path = mPathPrefix + mNames[stream];
143     unique_fd fileFd{::open(path.c_str(), O_RDONLY)};
144     unique_fd epollFd{epoll_create(1)};
145     epoll_event event = {
146             .events = EPOLLPRI | EPOLLET,
147     };
148     T actual;
149     bool ret;
150     int epollRet;
151 
152     if (timeoutMs < -1) {
153         ALOGE("Invalid polling timeout!");
154         return false;
155     }
156 
157     if (epoll_ctl(epollFd, EPOLL_CTL_ADD, fileFd, &event)) {
158         ALOGE("Failed to poll %s (%d): %s", mNames[stream].c_str(), errno, strerror(errno));
159         return false;
160     }
161 
162     while ((ret = get(&actual, stream)) && (actual != value)) {
163         epollRet = epoll_wait(epollFd, &event, 1, timeoutMs);
164         if (epollRet <= 0) {
165             ALOGE("Polling error or timeout! (%d)", epollRet);
166             return false;
167         }
168     }
169 
170     HWAPI_RECORD(value, stream);
171     return ret;
172 }
173 
174 template <typename T>
record(const char * func,const T & value,const std::ios * stream)175 void HwApiBase::record(const char *func, const T &value, const std::ios *stream) {
176     std::lock_guard<std::mutex> lock(mRecordsMutex);
177     mRecords.emplace_back(std::make_unique<Record<T>>(func, value, stream));
178     mRecords.pop_front();
179 }
180 
181 template <typename T>
toString(const NamesMap & names)182 std::string HwApiBase::Record<T>::toString(const NamesMap &names) {
183     using utils::operator<<;
184     std::stringstream ret;
185     auto lTp = std::chrono::system_clock::to_time_t(mTp);
186     struct tm buf;
187     auto lTime = localtime_r(&lTp, &buf);
188 
189     ret << std::put_time(lTime, "%Y-%m-%d %H:%M:%S.") << std::setfill('0') << std::setw(3)
190         << (std::chrono::duration_cast<std::chrono::milliseconds>(mTp.time_since_epoch()) % 1000)
191                     .count()
192         << "    " << mFunc << " '" << names.at(mStream) << "' = '" << mValue << "'";
193     return ret.str();
194 }
195 
196 class HwCalBase {
197   public:
198     HwCalBase();
199     void debug(int fd);
200 
201   protected:
202     template <typename T>
203     bool getProperty(const char *key, T *value, const T defval);
204     template <typename T>
205     bool getPersist(const char *key, T *value);
206 
207   private:
208     std::string mPropertyPrefix;
209     std::map<std::string, std::string> mCalData;
210 };
211 
212 template <typename T>
getProperty(const char * key,T * outval,const T defval)213 bool HwCalBase::getProperty(const char *key, T *outval, const T defval) {
214     ATRACE_NAME("HwCal::getProperty");
215     *outval = utils::getProperty(mPropertyPrefix + key, defval);
216     return true;
217 }
218 
219 template <typename T>
getPersist(const char * key,T * value)220 bool HwCalBase::getPersist(const char *key, T *value) {
221     ATRACE_NAME("HwCal::getPersist");
222     auto it = mCalData.find(key);
223     if (it == mCalData.end()) {
224         ALOGE("Missing %s config!", key);
225         return false;
226     }
227     std::stringstream stream{it->second};
228     utils::unpack(stream, value);
229     if (!stream || !stream.eof()) {
230         ALOGE("Invalid %s config!", key);
231         return false;
232     }
233     return true;
234 }
235 
236 }  // namespace vibrator
237 }  // namespace hardware
238 }  // namespace android
239 }  // namespace aidl
240