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