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 #define LOG_TAG "NanohubHAL" 18 19 #include <fcntl.h> 20 #include <poll.h> 21 #include <unistd.h> 22 #include <sys/inotify.h> 23 #include <sys/types.h> 24 #include <sys/stat.h> 25 26 #include <hardware/context_hub.h> 27 #include <hardware/hardware.h> 28 29 #include <cutils/properties.h> 30 #include <log/log.h> 31 32 #include <nanohub/nanohub.h> 33 34 #include <cinttypes> 35 #include <iomanip> 36 #include <sstream> 37 38 #include "nanohub_perdevice.h" 39 #include "system_comms.h" 40 #include "nanohubhal.h" 41 42 #define NANOHUB_LOCK_DIR "/data/vendor/sensor/nanohub_lock" 43 #define NANOHUB_LOCK_FILE NANOHUB_LOCK_DIR "/lock" 44 #define NANOHUB_LOCK_DIR_PERMS (S_IRUSR | S_IWUSR | S_IXUSR) 45 46 namespace android { 47 48 namespace nanohub { 49 50 inline std::ostream &operator << (std::ostream &os, const hub_app_name_t &appId) 51 { 52 char vendor[6]; 53 __be64 beAppId = htobe64(appId.id); 54 uint32_t seqId = appId.id & NANOAPP_VENDOR_ALL_APPS; 55 56 std::ios::fmtflags f(os.flags()); 57 memcpy(vendor, (void*)&beAppId, sizeof(vendor) - 1); 58 vendor[sizeof(vendor) - 1] = 0; 59 if (strlen(vendor) == 5) 60 os << vendor << ", " << std::hex << std::setw(6) << seqId; 61 else 62 os << "#" << std::hex << appId.id; 63 os.flags(f); 64 65 return os; 66 } 67 68 void dumpBuffer(const char *pfx, const hub_app_name_t &appId, uint32_t evtId, uint16_t endpoint, const void *data, size_t len, int status) 69 { 70 std::ostringstream os; 71 const uint8_t *p = static_cast<const uint8_t *>(data); 72 os << pfx << ": [ID=" << appId << "; SZ=" << std::dec << len; 73 if (evtId) 74 os << "; EVT=" << std::hex << evtId; 75 if (endpoint) 76 os << "; EPT=" << std::hex << endpoint; 77 os << "]:" << std::hex; 78 for (size_t i = 0; i < len; ++i) { 79 os << " " << std::setfill('0') << std::setw(2) << (unsigned int)p[i]; 80 } 81 if (status) { 82 os << "; status=" << status << " [" << std::setfill('0') << std::setw(8) << status << "]"; 83 } 84 ALOGI("%s", os.str().c_str()); 85 } 86 87 static int rwrite(int fd, const void *buf, int len) 88 { 89 int ret; 90 91 do { 92 ret = write(fd, buf, len); 93 } while (ret < 0 && errno == EINTR); 94 95 if (ret != len) { 96 return errno ? -errno : -EIO; 97 } 98 99 return 0; 100 } 101 102 static int rread(int fd, void *buf, int len) 103 { 104 int ret; 105 106 do { 107 ret = read(fd, buf, len); 108 } while (ret < 0 && errno == EINTR); 109 110 return ret; 111 } 112 113 static bool init_inotify(pollfd *pfd) { 114 bool success = false; 115 116 mkdir(NANOHUB_LOCK_DIR, NANOHUB_LOCK_DIR_PERMS); 117 pfd->fd = inotify_init1(IN_NONBLOCK); 118 if (pfd->fd < 0) { 119 ALOGE("Couldn't initialize inotify: %s", strerror(errno)); 120 } else if (inotify_add_watch(pfd->fd, NANOHUB_LOCK_DIR, IN_CREATE | IN_DELETE) < 0) { 121 ALOGE("Couldn't add inotify watch: %s", strerror(errno)); 122 close(pfd->fd); 123 } else { 124 pfd->events = POLLIN; 125 success = true; 126 } 127 128 return success; 129 } 130 131 static void discard_inotify_evt(pollfd &pfd) { 132 if ((pfd.revents & POLLIN)) { 133 char buf[sizeof(inotify_event) + NAME_MAX + 1]; 134 int ret = read(pfd.fd, buf, sizeof(buf)); 135 ALOGD("Discarded %d bytes of inotify data", ret); 136 } 137 } 138 139 static void wait_on_dev_lock(pollfd &pfd) { 140 // While the lock file exists, poll on the inotify fd (with timeout) 141 discard_inotify_evt(pfd); 142 while (access(NANOHUB_LOCK_FILE, F_OK) == 0) { 143 ALOGW("Nanohub is locked; blocking read thread"); 144 int ret = TEMP_FAILURE_RETRY(poll(&pfd, 1, 5000)); 145 if (ret < 0) { 146 ALOGE("poll returned with an error: %s", strerror(errno)); 147 break; 148 } else if (ret > 0) { 149 discard_inotify_evt(pfd); 150 } 151 } 152 } 153 154 NanoHub::NanoHub() { 155 reset(); 156 } 157 158 NanoHub::~NanoHub() { 159 if (mMsgCbkFunc) { 160 ALOGD("Shutting down"); 161 closeHub(); 162 } 163 } 164 165 int NanoHub::doSendToDevice(const hub_app_name_t name, const void *data, uint32_t len, uint32_t messageType, uint16_t endpoint) 166 { 167 if (len > MAX_RX_PACKET) { 168 return -EINVAL; 169 } 170 171 // transmit message to FW in CHRE format 172 nano_message_chre msg = { 173 .hdr = { 174 .eventId = APP_FROM_HOST_CHRE_EVENT_ID, 175 .appId = name.id, 176 .len = static_cast<uint8_t>(len), 177 .appEventId = messageType, 178 .endpoint = endpoint, 179 }, 180 }; 181 182 memcpy(&msg.data[0], data, len); 183 184 return rwrite(mFd, &msg, len + sizeof(msg.hdr)); 185 } 186 187 void NanoHub::doSendToApp(HubMessage &&msg) 188 { 189 std::unique_lock<std::mutex> lk(mAppTxLock); 190 mAppTxQueue.push_back((HubMessage &&)msg); 191 lk.unlock(); 192 mAppTxCond.notify_all(); 193 } 194 195 void NanoHub::doDumpAppInfo(std::string &result) 196 { 197 SystemComm::dumpAppInfo(result); 198 } 199 200 void* NanoHub::runAppTx() 201 { 202 std::unique_lock<std::mutex> lk(mAppTxLock); 203 while(true) { 204 mAppTxCond.wait(lk, [this] { return !mAppTxQueue.empty() || mAppQuit; }); 205 if (mAppQuit) { 206 break; 207 } 208 HubMessage &m = mAppTxQueue.front(); 209 lk.unlock(); 210 mMsgCbkFunc(0, m, mMsgCbkData); 211 lk.lock(); 212 mAppTxQueue.pop_front(); 213 }; 214 return NULL; 215 } 216 217 void* NanoHub::runDeviceRx() 218 { 219 enum { 220 IDX_NANOHUB, 221 IDX_CLOSE_PIPE, 222 IDX_INOTIFY 223 }; 224 pollfd myFds[3] = { 225 [IDX_NANOHUB] = { .fd = mFd, .events = POLLIN, }, 226 [IDX_CLOSE_PIPE] = { .fd = mThreadClosingPipe[0], .events = POLLIN, }, 227 }; 228 pollfd &inotifyFd = myFds[IDX_INOTIFY]; 229 bool hasInotify = false; 230 int numPollFds = 2; 231 232 if (init_inotify(&inotifyFd)) { 233 numPollFds++; 234 hasInotify = true; 235 } 236 237 setDebugFlags(property_get_int32("persist.nanohub.debug", 0)); 238 239 while (1) { 240 int ret = TEMP_FAILURE_RETRY(poll(myFds, numPollFds, -1)); 241 if (ret == 0) 242 continue; 243 else if (ret < 0) { 244 ALOGE("poll returned with an error: %s", strerror(errno)); 245 break; 246 } 247 248 if (hasInotify) { 249 wait_on_dev_lock(inotifyFd); 250 } 251 252 if (myFds[IDX_NANOHUB].revents & POLLIN) { // we have data 253 254 nano_message msg; 255 256 ret = rread(mFd, &msg, sizeof(msg)); 257 if (ret <= 0) { 258 ALOGE("read failed with %d", ret); 259 break; 260 } 261 if (ret < (int)sizeof(msg.raw.hdr)) { 262 ALOGE("Only read %d bytes", ret); 263 break; 264 } 265 266 uint32_t len = msg.raw.hdr.len; 267 268 if (len > MAX_RX_PACKET) { 269 ALOGE("malformed packet with len %" PRIu32, len); 270 break; 271 } 272 273 // receive message from FW in legacy format 274 if (ret == (int)(sizeof(msg.raw.hdr) + len)) { 275 ret = SystemComm::handleRx(&msg.raw); 276 if (ret > 0) { 277 hub_app_name_t app_name = { .id = msg.raw.hdr.appId }; 278 if (messageTracingEnabled()) { 279 dumpBuffer("(RAW) DEV -> APP", app_name, msg.raw.hdr.eventId, 0, &msg.raw.data[0], len); 280 } 281 doSendToApp(HubMessage(&app_name, msg.raw.hdr.eventId, ENDPOINT_BROADCAST, &msg.raw.data[0], len)); 282 } 283 // receive message from FW in chre format 284 } else if (ret == (int)(sizeof(msg.chre.hdr) + len)) { 285 ret = SystemComm::handleRx(&msg.chre); 286 if (ret > 0) { 287 hub_app_name_t app_name = { .id = msg.chre.hdr.appId }; 288 if (messageTracingEnabled()) { 289 dumpBuffer("(CHRE) DEV -> APP", app_name, msg.chre.hdr.appEventId, msg.chre.hdr.endpoint, &msg.chre.data[0], len); 290 } 291 doSendToApp(HubMessage(&app_name, msg.chre.hdr.appEventId, msg.chre.hdr.endpoint, &msg.chre.data[0], len)); 292 } 293 } else { 294 ALOGE("Expected (%zu|%zu) bytes, read %d bytes", sizeof(msg.raw.hdr) + len, sizeof(msg.chre.hdr) + len, ret); 295 break; 296 } 297 298 if (ret < 0) 299 ALOGE("SystemComm::handleRx() returned %d", ret); 300 } 301 302 if (myFds[IDX_CLOSE_PIPE].revents & POLLIN) { // we have been asked to die 303 ALOGD("thread exiting"); 304 break; 305 } 306 } 307 308 close(mFd); 309 return NULL; 310 } 311 312 int NanoHub::openHub() 313 { 314 int ret = 0; 315 316 mFd = open(get_devnode_path(), O_RDWR); 317 if (mFd < 0) { 318 ALOGE("cannot find hub devnode '%s'", get_devnode_path()); 319 ret = -errno; 320 goto fail_open; 321 } 322 323 if (pipe(mThreadClosingPipe)) { 324 ALOGE("failed to create signal pipe"); 325 ret = -errno; 326 goto fail_pipe; 327 } 328 329 mPollThread = std::thread([this] { runDeviceRx(); }); 330 mAppThread = std::thread([this] { runAppTx(); }); 331 return 0; 332 333 fail_pipe: 334 close(mFd); 335 336 fail_open: 337 return ret; 338 } 339 340 int NanoHub::closeHub(void) 341 { 342 char zero = 0; 343 344 // stop mPollThread 345 while(write(mThreadClosingPipe[1], &zero, 1) != 1) { 346 continue; 347 } 348 349 // stop mAppThread 350 { 351 std::unique_lock<std::mutex> lk(mAppTxLock); 352 mAppQuit = true; 353 lk.unlock(); 354 mAppTxCond.notify_all(); 355 } 356 357 //wait 358 if (mPollThread.joinable()) { 359 mPollThread.join(); 360 } 361 362 //wait 363 if (mAppThread.joinable()) { 364 mAppThread.join(); 365 } 366 //cleanup 367 ::close(mThreadClosingPipe[0]); 368 ::close(mThreadClosingPipe[1]); 369 ::close(mFd); 370 371 reset(); 372 373 return 0; 374 } 375 376 int NanoHub::doSubscribeMessages(uint32_t hub_id, Contexthub_callback *cbk, void *cookie) 377 { 378 if (hub_id) { 379 return -ENODEV; 380 } 381 382 std::lock_guard<std::mutex> _l(mLock); 383 int ret = 0; 384 385 if (!mMsgCbkFunc && !cbk) { //we're off and staying off - do nothing 386 387 ALOGD("staying off"); 388 } else if (cbk && mMsgCbkFunc) { //new callback but staying on 389 390 ALOGD("staying on"); 391 } else if (mMsgCbkFunc) { //we were on but turning off 392 393 ALOGD("turning off"); 394 395 ret = closeHub(); 396 } else if (cbk) { //we're turning on 397 398 ALOGD("turning on"); 399 ret = openHub(); 400 } 401 402 mMsgCbkFunc = cbk; 403 mMsgCbkData = cookie; 404 405 return ret; 406 } 407 408 int NanoHub::doSendToNanohub(uint32_t hub_id, const hub_message_t *msg, uint32_t transaction_id, uint16_t endpoint) 409 { 410 if (hub_id) { 411 return -ENODEV; 412 } 413 414 int ret = 0; 415 std::lock_guard<std::mutex> _l(mLock); 416 417 if (!mMsgCbkFunc) { 418 ALOGW("refusing to send a message when nobody around to get a reply!"); 419 ret = -EIO; 420 } else { 421 if (!msg || !msg->message) { 422 ALOGW("not sending invalid message 1"); 423 ret = -EINVAL; 424 } else if (get_hub_info()->os_app_name == msg->app_name) { 425 //messages to the "system" app are special - hal handles them 426 if (messageTracingEnabled()) { 427 dumpBuffer("APP -> HAL", msg->app_name, msg->message_type, 0, msg->message, msg->message_len); 428 } 429 ret = SystemComm::handleTx(msg, transaction_id); 430 } else if (msg->message_len > MAX_RX_PACKET) { 431 ALOGW("not sending invalid message 2"); 432 ret = -EINVAL; 433 } else { 434 if (messageTracingEnabled()) { 435 dumpBuffer("APP -> DEV", msg->app_name, msg->message_type, endpoint, msg->message, msg->message_len); 436 } 437 ret = doSendToDevice(msg->app_name, msg->message, msg->message_len, msg->message_type, endpoint); 438 } 439 } 440 441 return ret; 442 } 443 444 }; // namespace nanohub 445 446 }; // namespace android 447