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 <cstdint>
18 #include <dlfcn.h>
19 
20 extern "C" {
21 
22 #include "qsh_na_api.h"
23 
24 }  // extern "C"
25 
26 #include "chre/core/event_loop_manager.h"
27 #include "chre/core/nanoapp.h"
28 #include "chre/platform/assert.h"
29 #include "chre/platform/log.h"
30 #include "chre/platform/memory.h"
31 #include "chre/platform/slpi/qsh/qsh_shim.h"
32 #include "chre/sensor.h"
33 #include "chre/util/macros.h"
34 
35 namespace chre {
36 namespace {
37 
38 //! Function pointer to store QSH's version of chreSensorFlushAsync
39 decltype(chreSensorFlushAsync) *gFlushFuncPtr = nullptr;
40 
41 /*
42  * Used by QSH to obtain the currently running nanoapp instance ID when nanoapps
43  * invoke CHRE APIs implemented by its shim.
44  */
getCurrentNanoappInstanceId(uint32_t * nanoappInstId)45 bool getCurrentNanoappInstanceId(uint32_t *nanoappInstId) {
46   CHRE_ASSERT(nanoappInstId != nullptr);
47   if (nanoappInstId == nullptr) {
48     return false;
49   }
50 
51   bool success = false;
52   Nanoapp *currentNanoapp =
53       EventLoopManagerSingleton::get()->getEventLoop().getCurrentNanoapp();
54   if (currentNanoapp == nullptr) {
55     LOGE("No nanoapp currently executing");
56   } else {
57     *nanoappInstId = currentNanoapp->getInstanceId();
58     success = true;
59   }
60   return success;
61 }
62 
63 /*
64  * Used by QSH to post events to the CHRE event loop. The caller continues to
65  * own the event pointer after returning so a copy must be made of the data.
66  */
postEventFromQsh(uint16_t eventType,void * event,uint32_t eventLen,uint32_t nanoappInstId)67 bool postEventFromQsh(uint16_t eventType, void *event, uint32_t eventLen,
68                       uint32_t nanoappInstId) {
69   // Default success to true if the event is empty since an empty event can
70   // still be sent to CHRE.
71   bool success = false;
72   void *eventCopy = nullptr;
73   if (eventLen == 0) {
74     CHRE_ASSERT(event == nullptr);
75     if (event != nullptr) {
76       LOGE("Event len 0 with non-null event data");
77     } else {
78       success = true;
79     }
80   } else {
81     CHRE_ASSERT(event != nullptr);
82     if (event != nullptr) {
83       eventCopy = memoryAlloc(eventLen);
84       if (eventCopy == nullptr) {
85         LOG_OOM();
86       } else {
87         memcpy(eventCopy, event, eventLen);
88         success = true;
89       }
90     }
91   }
92 
93   if (success) {
94     EventLoopManagerSingleton::get()->getEventLoop().postEventOrDie(
95         eventType, eventCopy, freeEventDataCallback, nanoappInstId);
96   }
97   return success;
98 }
99 
100 const qsh_na_api_callbacks gQshCallbacks = {
101     getCurrentNanoappInstanceId, /* get_current_nanoapp_inst_id */
102     postEventFromQsh,            /* post_event */
103 };
104 
105 }  // anonymous namespace
106 
openQsh()107 void openQsh() {
108   if (!qsh_na_open(&gQshCallbacks)) {
109     LOGE("QSH failed to open");
110   } else {
111     LOGI("QSH opened");
112     gFlushFuncPtr = reinterpret_cast<decltype(gFlushFuncPtr)>(
113         dlsym(RTLD_NEXT, STRINGIFY(chreSensorFlushAsync)));
114     if (gFlushFuncPtr == nullptr) {
115       LOGE("Flush function not found!");
116     }
117   }
118 }
119 
closeQsh()120 void closeQsh() {
121   qsh_na_close();
122 }
123 
124 }  // namespace chre
125 
126 // Define the delete operator so that SLPI doesn't have to expose this symbol
127 // since CHRE will never call it directly
operator delete(void * ptr)128 void operator delete (void* ptr) noexcept {
129   free(ptr);
130 }
131 
132 // Export the chreSensorFlushAsync symbol from CHRE and then used the previously
133 // looked up symbol to WAR loader issue where nanoapps can't see QSH symbols.
chreSensorFlushAsync(uint32_t sensorHandle,const void * cookie)134 DLL_EXPORT extern "C" bool chreSensorFlushAsync(uint32_t sensorHandle,
135                                                 const void *cookie) {
136   return (chre::gFlushFuncPtr != nullptr)
137       ? chre::gFlushFuncPtr(sensorHandle, cookie)
138       : false;
139 }