1 /*
2  * Copyright (C) 2016 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 
17 #include "androidcontexthub.h"
18 
19 #include <errno.h>
20 #include <fcntl.h>
21 #include <poll.h>
22 #include <time.h>
23 #include <unistd.h>
24 #include <sys/stat.h>
25 
26 #include <chrono>
27 #include <cstdint>
28 #include <cstdio>
29 #include <cstring>
30 #include <thread>
31 #include <vector>
32 
33 #include "calibrationfile.h"
34 #include "log.h"
35 
36 namespace android {
37 
38 constexpr char kSensorDeviceFile[] = "/dev/nanohub";
39 constexpr char kCommsDeviceFile[] = "/dev/nanohub_comms";
40 constexpr char kLockDirectory[] = "/data/vendor/sensor/nanohub_lock";
41 constexpr char kLockFile[] = "/data/vendor/sensor/nanohub_lock/lock";
42 
43 constexpr mode_t kLockDirPermissions = (S_IRUSR | S_IWUSR | S_IXUSR);
44 
45 constexpr auto kLockDelay = std::chrono::milliseconds(100);
46 
47 constexpr int kDeviceFileCount = 2;
48 constexpr int kPollNoTimeout = -1;
49 
50 static const std::vector<std::tuple<const char *, SensorType>> kCalibrationKeys = {
51     std::make_tuple("accel",     SensorType::Accel),
52     std::make_tuple("gyro",      SensorType::Gyro),
53     std::make_tuple("proximity", SensorType::Proximity),
54     std::make_tuple("barometer", SensorType::Barometer),
55     std::make_tuple("light",     SensorType::AmbientLightSensor),
56 };
57 
AppendBytes(const void * data,size_t length,std::vector<uint8_t> & buffer)58 static void AppendBytes(const void *data, size_t length, std::vector<uint8_t>& buffer) {
59     const uint8_t *bytes = (const uint8_t *) data;
60     for (size_t i = 0; i < length; i++) {
61         buffer.push_back(bytes[i]);
62     }
63 }
64 
CopyInt32Array(const char * key,sp<JSONObject> json,std::vector<uint8_t> & bytes)65 static bool CopyInt32Array(const char *key,
66         sp<JSONObject> json, std::vector<uint8_t>& bytes) {
67     sp<JSONArray> array;
68     if (json->getArray(key, &array)) {
69         for (size_t i = 0; i < array->size(); i++) {
70             int32_t val = 0;
71             array->getInt32(i, &val);
72             AppendBytes(&val, sizeof(uint32_t), bytes);
73         }
74 
75         return true;
76     }
77     return false;
78 }
79 
GetCalibrationBytes(const char * key,SensorType sensor_type,std::vector<uint8_t> & bytes)80 static bool GetCalibrationBytes(const char *key, SensorType sensor_type,
81         std::vector<uint8_t>& bytes) {
82     bool success = true;
83     std::shared_ptr<CalibrationFile> cal_file = CalibrationFile::Instance();
84     if (!cal_file) {
85         return false;
86     }
87     auto json = cal_file->GetJSONObject();
88 
89     switch (sensor_type) {
90       case SensorType::Accel:
91       case SensorType::Gyro:
92         success = CopyInt32Array(key, json, bytes);
93         break;
94 
95       case SensorType::AmbientLightSensor:
96       case SensorType::Barometer: {
97         float value = 0;
98         success = json->getFloat(key, &value);
99         if (success) {
100             AppendBytes(&value, sizeof(float), bytes);
101         }
102         break;
103       }
104 
105       case SensorType::Proximity: {
106         // Proximity might be an int32 array with 4 values (CRGB) or a single
107         // int32 value - try both
108         success = CopyInt32Array(key, json, bytes);
109         if (!success) {
110             int32_t value = 0;
111             success = json->getInt32(key, &value);
112             if (success) {
113                 AppendBytes(&value, sizeof(int32_t), bytes);
114             }
115         }
116         break;
117       }
118 
119       default:
120         // If this log message gets printed, code needs to be added in this
121         // switch statement
122         LOGE("Missing sensor type to calibration data mapping sensor %d",
123              static_cast<int>(sensor_type));
124         success = false;
125     }
126 
127     return success;
128 }
129 
~AndroidContextHub()130 AndroidContextHub::~AndroidContextHub() {
131     if (unlink(kLockFile) < 0) {
132         LOGE("Couldn't remove lock file: %s", strerror(errno));
133     }
134     if (sensor_fd_ >= 0) {
135         DisableActiveSensors();
136         (void) close(sensor_fd_);
137     }
138     if (comms_fd_ >= 0) {
139         (void) close(comms_fd_);
140     }
141 }
142 
TerminateHandler()143 void AndroidContextHub::TerminateHandler() {
144     (void) unlink(kLockFile);
145 }
146 
Initialize()147 bool AndroidContextHub::Initialize() {
148     // Acquire a lock on nanohub, so the HAL read threads won't take our events.
149     // We need to delay after creating the file to have good confidence that
150     // the HALs noticed the lock file creation.
151     if (access(kLockDirectory, F_OK) < 0) {
152         if (mkdir(kLockDirectory, kLockDirPermissions) < 0 && errno != EEXIST) {
153             LOGE("Couldn't create lock directory: %s", strerror(errno));
154         }
155     }
156     int lock_fd = open(kLockFile, O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
157     if (lock_fd < 0) {
158         LOGE("Couldn't create lock file: %s", strerror(errno));
159         if (errno != EEXIST) {
160             return false;
161         }
162     } else {
163         close(lock_fd);
164         std::this_thread::sleep_for(kLockDelay);
165         LOGD("Lock sleep complete");
166     }
167 
168     // Sensor device file is used for sensor requests, e.g. configure, etc., and
169     // returns sensor events
170     sensor_fd_ = open(kSensorDeviceFile, O_RDWR);
171     if (sensor_fd_ < 0) {
172         LOGE("Couldn't open device file: %s", strerror(errno));
173         return false;
174     }
175 
176     // The comms device file is used for more generic communication with
177     // nanoapps. Calibration results are returned through this channel.
178     comms_fd_ = open(kCommsDeviceFile, O_RDONLY);
179     if (comms_fd_ < 0) {
180         // TODO(bduddie): Currently informational only, as the kernel change
181         // that adds this device file is not available/propagated yet.
182         // Eventually this should be an error.
183         LOGI("Couldn't open comms device file: %s", strerror(errno));
184     }
185 
186     return true;
187 }
188 
SetLoggingEnabled(bool logging_enabled)189 void AndroidContextHub::SetLoggingEnabled(bool logging_enabled) {
190     if (logging_enabled) {
191         LOGE("Logging is not supported on this platform");
192     }
193 }
194 
WriteEvent(const std::vector<uint8_t> & message)195 ContextHub::TransportResult AndroidContextHub::WriteEvent(
196         const std::vector<uint8_t>& message) {
197     ContextHub::TransportResult result;
198 
199     LOGD("Writing %zu bytes", message.size());
200     LOGD_BUF(message.data(), message.size());
201     int ret = write(sensor_fd_, message.data(), message.size());
202     if (ret == -1) {
203         LOGE("Couldn't write %zu bytes to device file: %s", message.size(),
204              strerror(errno));
205         result = TransportResult::GeneralFailure;
206     } else if (ret != (int) message.size()) {
207         LOGW("Write returned %d, expected %zu", ret, message.size());
208         result = TransportResult::GeneralFailure;
209     } else {
210         LOGD("Successfully sent event");
211         result = TransportResult::Success;
212     }
213 
214     return result;
215 }
216 
ReadEvent(std::vector<uint8_t> & message,int timeout_ms)217 ContextHub::TransportResult AndroidContextHub::ReadEvent(
218         std::vector<uint8_t>& message, int timeout_ms) {
219     ContextHub::TransportResult result = TransportResult::GeneralFailure;
220 
221     struct pollfd pollfds[kDeviceFileCount];
222     int fd_count = ResetPollFds(pollfds, kDeviceFileCount);
223 
224     int timeout = timeout_ms > 0 ? timeout_ms : kPollNoTimeout;
225     int ret = poll(pollfds, fd_count, timeout);
226     if (ret < 0) {
227         LOGE("Polling failed: %s", strerror(errno));
228         if (errno == EINTR) {
229             result = TransportResult::Canceled;
230         }
231     } else if (ret == 0) {
232         LOGD("Poll timed out");
233         result = TransportResult::Timeout;
234     } else {
235         int read_fd = -1;
236         for (int i = 0; i < kDeviceFileCount; i++) {
237             if (pollfds[i].revents & POLLIN) {
238                 read_fd = pollfds[i].fd;
239                 break;
240             }
241         }
242 
243         if (read_fd == sensor_fd_) {
244             LOGD("Data ready on sensors device file");
245         } else if (read_fd == comms_fd_) {
246             LOGD("Data ready on comms device file");
247         }
248 
249         if (read_fd >= 0) {
250             result = ReadEventFromFd(read_fd, message);
251         } else {
252             LOGE("Poll returned but none of expected files are ready");
253         }
254     }
255 
256     return result;
257 }
258 
FlashSensorHub(const std::vector<uint8_t> & bytes)259 bool AndroidContextHub::FlashSensorHub(const std::vector<uint8_t>& bytes) {
260     (void)bytes;
261     LOGE("Flashing is not supported on this platform");
262     return false;
263 }
264 
LoadCalibration()265 bool AndroidContextHub::LoadCalibration() {
266     std::vector<uint8_t> cal_data;
267     bool success = true;
268 
269     for (size_t i = 0; success && i < kCalibrationKeys.size(); i++) {
270         std::string key;
271         SensorType sensor_type;
272 
273         std::tie(key, sensor_type) = kCalibrationKeys[i];
274         if (GetCalibrationBytes(key.c_str(), sensor_type, cal_data)) {
275             success = SendCalibrationData(sensor_type, cal_data);
276         }
277 
278         cal_data.clear();
279     }
280 
281     return success;
282 }
283 
SetCalibration(SensorType sensor_type,int32_t data)284 bool AndroidContextHub::SetCalibration(SensorType sensor_type, int32_t data) {
285     LOGI("Setting calibration for sensor %d (%s) to %d",
286          static_cast<int>(sensor_type),
287          ContextHub::SensorTypeToAbbrevName(sensor_type).c_str(), data);
288     auto cal_file = CalibrationFile::Instance();
289     const char *key = AndroidContextHub::SensorTypeToCalibrationKey(sensor_type);
290     if (cal_file && key) {
291         return cal_file->SetSingleAxis(key, data);
292     }
293     return false;
294 }
295 
SetCalibration(SensorType sensor_type,float data)296 bool AndroidContextHub::SetCalibration(SensorType sensor_type, float data) {
297     LOGI("Setting calibration for sensor %d (%s) to %f",
298          static_cast<int>(sensor_type),
299          ContextHub::SensorTypeToAbbrevName(sensor_type).c_str(), data);
300     auto cal_file = CalibrationFile::Instance();
301     const char *key = AndroidContextHub::SensorTypeToCalibrationKey(sensor_type);
302     if (cal_file && key) {
303         return cal_file->SetSingleAxis(key, data);
304     }
305     return false;
306 }
307 
SetCalibration(SensorType sensor_type,int32_t x,int32_t y,int32_t z)308 bool AndroidContextHub::SetCalibration(SensorType sensor_type, int32_t x,
309         int32_t y, int32_t z) {
310     LOGI("Setting calibration for %d to %d %d %d", static_cast<int>(sensor_type),
311          x, y, z);
312     auto cal_file = CalibrationFile::Instance();
313     const char *key = AndroidContextHub::SensorTypeToCalibrationKey(sensor_type);
314     if (cal_file && key) {
315         return cal_file->SetTripleAxis(key, x, y, z);
316     }
317     return false;
318 }
319 
SetCalibration(SensorType sensor_type,int32_t x,int32_t y,int32_t z,int32_t w)320 bool AndroidContextHub::SetCalibration(SensorType sensor_type, int32_t x,
321         int32_t y, int32_t z, int32_t w) {
322     LOGI("Setting calibration for %d to %d %d %d %d", static_cast<int>(sensor_type),
323          x, y, z, w);
324     auto cal_file = CalibrationFile::Instance();
325     const char *key = AndroidContextHub::SensorTypeToCalibrationKey(sensor_type);
326     if (cal_file && key) {
327         return cal_file->SetFourAxis(key, x, y, z, w);
328     }
329     return false;
330 }
331 
SaveCalibration()332 bool AndroidContextHub::SaveCalibration() {
333     LOGI("Saving calibration data");
334     auto cal_file = CalibrationFile::Instance();
335     if (cal_file) {
336         return cal_file->Save();
337     }
338     return false;
339 }
340 
ReadEventFromFd(int fd,std::vector<uint8_t> & message)341 ContextHub::TransportResult AndroidContextHub::ReadEventFromFd(
342         int fd, std::vector<uint8_t>& message) {
343     ContextHub::TransportResult result = TransportResult::GeneralFailure;
344 
345     // Set the size to the maximum, so when we resize later, it's always a
346     // shrink (otherwise it will end up clearing the bytes)
347     message.resize(message.capacity());
348 
349     LOGD("Calling into read()");
350     int ret = read(fd, message.data(), message.capacity());
351     if (ret < 0) {
352         LOGE("Couldn't read from device file: %s", strerror(errno));
353         if (errno == EINTR) {
354             result = TransportResult::Canceled;
355         }
356     } else if (ret == 0) {
357         // We might need to handle this specially, if the driver implements this
358         // to mean something specific
359         LOGE("Read unexpectedly returned 0 bytes");
360     } else {
361         message.resize(ret);
362         LOGD_VEC(message);
363         result = TransportResult::Success;
364     }
365 
366     return result;
367 }
368 
ResetPollFds(struct pollfd * pfds,size_t count)369 int AndroidContextHub::ResetPollFds(struct pollfd *pfds, size_t count) {
370     memset(pfds, 0, sizeof(struct pollfd) * count);
371     pfds[0].fd = sensor_fd_;
372     pfds[0].events = POLLIN;
373 
374     int nfds = 1;
375     if (count > 1 && comms_fd_ >= 0) {
376         pfds[1].fd = comms_fd_;
377         pfds[1].events = POLLIN;
378         nfds++;
379     }
380     return nfds;
381 }
382 
SensorTypeToCalibrationKey(SensorType sensor_type)383 const char *AndroidContextHub::SensorTypeToCalibrationKey(SensorType sensor_type) {
384     for (size_t i = 0; i < kCalibrationKeys.size(); i++) {
385         const char *key;
386         SensorType sensor_type_for_key;
387 
388         std::tie(key, sensor_type_for_key) = kCalibrationKeys[i];
389         if (sensor_type == sensor_type_for_key) {
390             return key;
391         }
392     }
393 
394     LOGE("No calibration key mapping for sensor type %d",
395          static_cast<int>(sensor_type));
396     return nullptr;
397 }
398 
399 }  // namespace android
400