Home | History | Annotate | Download | only in contexthubhal
      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