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