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