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 "chre/platform/shared/nanoapp_support_lib_dso.h"
18
19 #include <chre.h>
20
21 #include "chre/platform/shared/debug_dump.h"
22 #include "chre/util/macros.h"
23 #include "chre/util/system/napp_permissions.h"
24 #ifdef CHRE_NANOAPP_USES_WIFI
25 #include "chre/util/system/wifi_util.h"
26 #endif
27
28 /**
29 * @file
30 * The Nanoapp Support Library (NSL) that gets built with nanoapps to act as an
31 * intermediary to the reference CHRE implementation. It provides hooks so the
32 * app can be registered with the system, and also provides a layer where we can
33 * implement cross-version compatibility features as needed.
34 */
35
36 namespace {
37
38 constexpr uint32_t kNanoappPermissions = 0
39 // DO NOT USE this macro outside of specific CHQTS nanoapps. This is only used
40 // to allow testing of invalid permission declarations.
41 #ifdef CHRE_TEST_NANOAPP_PERMS
42 | CHRE_TEST_NANOAPP_PERMS
43 #else
44 #ifdef CHRE_NANOAPP_USES_AUDIO
45 | static_cast<uint32_t>(
46 chre::NanoappPermissions::
47 CHRE_PERMS_AUDIO)
48 #endif
49 #ifdef CHRE_NANOAPP_USES_GNSS
50 | static_cast<uint32_t>(
51 chre::NanoappPermissions::
52 CHRE_PERMS_GNSS)
53 #endif
54 #ifdef CHRE_NANOAPP_USES_WIFI
55 | static_cast<uint32_t>(
56 chre::NanoappPermissions::
57 CHRE_PERMS_WIFI)
58 #endif
59 #ifdef CHRE_NANOAPP_USES_WWAN
60 | static_cast<uint32_t>(
61 chre::NanoappPermissions::
62 CHRE_PERMS_WWAN)
63 #endif
64 #endif // CHRE_TEST_NANOAPP_PERMS
65 ;
66
67 #if defined(CHRE_SLPI_UIMG_ENABLED) || defined(CHRE_TCM_ENABLED)
68 constexpr int kIsTcmNanoapp = 1;
69 #else
70 constexpr int kIsTcmNanoapp = 0;
71 #endif // CHRE_SLPI_UIMG_ENABLED
72
73 #if !defined(CHRE_NANOAPP_DISABLE_BACKCOMPAT) && defined(CHRE_NANOAPP_USES_GNSS)
74 // Return a v1.3+ GnssLocationEvent for the nanoapp when running on a v1.2-
75 // platform.
translateLegacyGnssLocation(const chreGnssLocationEvent & legacyEvent)76 chreGnssLocationEvent translateLegacyGnssLocation(
77 const chreGnssLocationEvent &legacyEvent) {
78 // Copy v1.2- fields over to a v1.3+ event.
79 chreGnssLocationEvent newEvent = {};
80 newEvent.timestamp = legacyEvent.timestamp;
81 newEvent.latitude_deg_e7 = legacyEvent.latitude_deg_e7;
82 newEvent.longitude_deg_e7 = legacyEvent.longitude_deg_e7;
83 newEvent.altitude = legacyEvent.altitude;
84 newEvent.speed = legacyEvent.speed;
85 newEvent.bearing = legacyEvent.bearing;
86 newEvent.accuracy = legacyEvent.accuracy;
87 newEvent.flags = legacyEvent.flags;
88
89 // Unset flags that are defined in v1.3+ but not in v1.2-.
90 newEvent.flags &= ~(CHRE_GPS_LOCATION_HAS_ALTITUDE_ACCURACY |
91 CHRE_GPS_LOCATION_HAS_SPEED_ACCURACY |
92 CHRE_GPS_LOCATION_HAS_BEARING_ACCURACY);
93 return newEvent;
94 }
95
nanoappHandleEventCompat(uint32_t senderInstanceId,uint16_t eventType,const void * eventData)96 void nanoappHandleEventCompat(uint32_t senderInstanceId, uint16_t eventType,
97 const void *eventData) {
98 if (eventType == CHRE_EVENT_GNSS_LOCATION &&
99 chreGetApiVersion() < CHRE_API_VERSION_1_3) {
100 chreGnssLocationEvent event = translateLegacyGnssLocation(
101 *static_cast<const chreGnssLocationEvent *>(eventData));
102 nanoappHandleEvent(senderInstanceId, eventType, &event);
103 } else {
104 nanoappHandleEvent(senderInstanceId, eventType, eventData);
105 }
106 }
107 #endif
108
109 } // anonymous namespace
110
111 //! Used to determine the given unstable ID that was provided when building this
112 //! nanoapp, if any. The symbol is placed in its own section so it can be
113 //! stripped to determine if the nanoapp changed compared to a previous version.
114 //! We also align the variable to match the minimum alignment of the surrounding
115 //! sections, since for compilers with a default size-1 alignment, there might
116 //! be a spill-over from the previous segment if not zero-padded, when we
117 //! attempt to read the string.
118 DLL_EXPORT extern "C" const char _chreNanoappUnstableId[]
119 __attribute__((section(".unstable_id"))) __attribute__((aligned(8))) =
120 NANOAPP_UNSTABLE_ID;
121
122 DLL_EXPORT extern "C" const struct chreNslNanoappInfo _chreNslDsoNanoappInfo = {
123 /* magic */ CHRE_NSL_NANOAPP_INFO_MAGIC,
124 /* structMinorVersion */ CHRE_NSL_NANOAPP_INFO_STRUCT_MINOR_VERSION,
125 /* isSystemNanoapp */ NANOAPP_IS_SYSTEM_NANOAPP,
126 /* isTcmNanoapp */ kIsTcmNanoapp,
127 /* reservedFlags */ 0,
128 /* reserved */ 0,
129 /* targetApiVersion */ CHRE_API_VERSION,
130
131 // These values are supplied by the build environment.
132 /* vendor */ NANOAPP_VENDOR_STRING,
133 /* name */ NANOAPP_NAME_STRING,
134 /* appId */ NANOAPP_ID,
135 /* appVersion */ NANOAPP_VERSION,
136 /* entryPoints */
137 {
138 /* start */ nanoappStart,
139 #if !defined(CHRE_NANOAPP_DISABLE_BACKCOMPAT) && defined(CHRE_NANOAPP_USES_GNSS)
140 /* handleEvent */ nanoappHandleEventCompat,
141 #else
142 /* handleEvent */ nanoappHandleEvent,
143 #endif
144 /* end */ nanoappEnd,
145 },
146 /* appVersionString */ _chreNanoappUnstableId,
147 /* appPermissions */ kNanoappPermissions,
148 };
149
150 // The code section below provides default implementations for new symbols
151 // introduced in CHRE API v1.2+ to provide binary compatibility with previous
152 // CHRE implementations. Note that we don't presently include symbols for v1.1,
153 // as the current known set of CHRE platforms that use this NSL implementation
154 // are all v1.1+.
155 // If a nanoapp knows that it is only targeting the latest platform version, it
156 // can define the CHRE_NANOAPP_DISABLE_BACKCOMPAT flag, so this indirection will
157 // be avoided at the expense of a nanoapp not being able to load at all on prior
158 // implementations.
159
160 #ifndef CHRE_NANOAPP_DISABLE_BACKCOMPAT
161
162 #include <dlfcn.h>
163
164 /**
165 * Lazily calls dlsym to find the function pointer for a given function
166 * (provided without quotes) in another library (i.e. the CHRE platform DSO),
167 * caching and returning the result.
168 */
169 #define CHRE_NSL_LAZY_LOOKUP(functionName) \
170 ({ \
171 static bool lookupPerformed = false; \
172 static decltype(functionName) *fptr = nullptr; \
173 if (!lookupPerformed) { \
174 fptr = reinterpret_cast<decltype(fptr)>( \
175 dlsym(RTLD_NEXT, STRINGIFY(functionName))); \
176 lookupPerformed = true; \
177 } \
178 fptr; \
179 })
180
181 #ifdef CHRE_NANOAPP_USES_AUDIO
182
183 WEAK_SYMBOL
chreAudioGetSource(uint32_t handle,struct chreAudioSource * audioSource)184 bool chreAudioGetSource(uint32_t handle, struct chreAudioSource *audioSource) {
185 auto *fptr = CHRE_NSL_LAZY_LOOKUP(chreAudioGetSource);
186 return (fptr != nullptr) ? fptr(handle, audioSource) : false;
187 }
188
189 WEAK_SYMBOL
chreAudioConfigureSource(uint32_t handle,bool enable,uint64_t bufferDuration,uint64_t deliveryInterval)190 bool chreAudioConfigureSource(uint32_t handle, bool enable,
191 uint64_t bufferDuration,
192 uint64_t deliveryInterval) {
193 auto *fptr = CHRE_NSL_LAZY_LOOKUP(chreAudioConfigureSource);
194 return (fptr != nullptr)
195 ? fptr(handle, enable, bufferDuration, deliveryInterval)
196 : false;
197 }
198
199 WEAK_SYMBOL
chreAudioGetStatus(uint32_t handle,struct chreAudioSourceStatus * status)200 bool chreAudioGetStatus(uint32_t handle, struct chreAudioSourceStatus *status) {
201 auto *fptr = CHRE_NSL_LAZY_LOOKUP(chreAudioGetStatus);
202 return (fptr != nullptr) ? fptr(handle, status) : false;
203 }
204
205 #endif /* CHRE_NANOAPP_USES_AUDIO */
206
207 WEAK_SYMBOL
chreConfigureHostSleepStateEvents(bool enable)208 void chreConfigureHostSleepStateEvents(bool enable) {
209 auto *fptr = CHRE_NSL_LAZY_LOOKUP(chreConfigureHostSleepStateEvents);
210 if (fptr != nullptr) {
211 fptr(enable);
212 }
213 }
214
215 WEAK_SYMBOL
chreIsHostAwake(void)216 bool chreIsHostAwake(void) {
217 auto *fptr = CHRE_NSL_LAZY_LOOKUP(chreIsHostAwake);
218 return (fptr != nullptr) ? fptr() : false;
219 }
220
221 #ifdef CHRE_NANOAPP_USES_GNSS
222
223 WEAK_SYMBOL
chreGnssConfigurePassiveLocationListener(bool enable)224 bool chreGnssConfigurePassiveLocationListener(bool enable) {
225 auto *fptr = CHRE_NSL_LAZY_LOOKUP(chreGnssConfigurePassiveLocationListener);
226 return (fptr != nullptr) ? fptr(enable) : false;
227 }
228
229 #endif /* CHRE_NANOAPP_USES_GNSS */
230
231 #ifdef CHRE_NANOAPP_USES_WIFI
232
233 WEAK_SYMBOL
chreWifiRequestScanAsync(const struct chreWifiScanParams * params,const void * cookie)234 bool chreWifiRequestScanAsync(const struct chreWifiScanParams *params,
235 const void *cookie) {
236 auto *fptr = CHRE_NSL_LAZY_LOOKUP(chreWifiRequestScanAsync);
237
238 if (fptr == nullptr) {
239 // Should never happen
240 return false;
241 } else if (chreGetApiVersion() < CHRE_API_VERSION_1_5) {
242 const struct chreWifiScanParams legacyParams =
243 chre::translateToLegacyWifiScanParams(params);
244 return fptr(&legacyParams, cookie);
245 } else {
246 return fptr(params, cookie);
247 }
248 }
249
250 WEAK_SYMBOL
chreWifiRequestRangingAsync(const struct chreWifiRangingParams * params,const void * cookie)251 bool chreWifiRequestRangingAsync(const struct chreWifiRangingParams *params,
252 const void *cookie) {
253 auto *fptr = CHRE_NSL_LAZY_LOOKUP(chreWifiRequestRangingAsync);
254 return (fptr != nullptr) ? fptr(params, cookie) : false;
255 }
256
257 #endif /* CHRE_NANOAPP_USES_WIFI */
258
259 WEAK_SYMBOL
chreSensorFind(uint8_t sensorType,uint8_t sensorIndex,uint32_t * handle)260 bool chreSensorFind(uint8_t sensorType, uint8_t sensorIndex, uint32_t *handle) {
261 auto *fptr = CHRE_NSL_LAZY_LOOKUP(chreSensorFind);
262 if (fptr != nullptr) {
263 return fptr(sensorType, sensorIndex, handle);
264 } else if (sensorIndex == 0) {
265 return chreSensorFindDefault(sensorType, handle);
266 } else {
267 return false;
268 }
269 }
270
271 WEAK_SYMBOL
chreSensorConfigureBiasEvents(uint32_t sensorHandle,bool enable)272 bool chreSensorConfigureBiasEvents(uint32_t sensorHandle, bool enable) {
273 auto *fptr = CHRE_NSL_LAZY_LOOKUP(chreSensorConfigureBiasEvents);
274 return (fptr != nullptr) ? fptr(sensorHandle, enable) : false;
275 }
276
277 WEAK_SYMBOL
chreSensorGetThreeAxisBias(uint32_t sensorHandle,struct chreSensorThreeAxisData * bias)278 bool chreSensorGetThreeAxisBias(uint32_t sensorHandle,
279 struct chreSensorThreeAxisData *bias) {
280 auto *fptr = CHRE_NSL_LAZY_LOOKUP(chreSensorGetThreeAxisBias);
281 return (fptr != nullptr) ? fptr(sensorHandle, bias) : false;
282 }
283
284 WEAK_SYMBOL
chreSensorFlushAsync(uint32_t sensorHandle,const void * cookie)285 bool chreSensorFlushAsync(uint32_t sensorHandle, const void *cookie) {
286 auto *fptr = CHRE_NSL_LAZY_LOOKUP(chreSensorFlushAsync);
287 return (fptr != nullptr) ? fptr(sensorHandle, cookie) : false;
288 }
289
290 WEAK_SYMBOL
chreConfigureDebugDumpEvent(bool enable)291 void chreConfigureDebugDumpEvent(bool enable) {
292 auto *fptr = CHRE_NSL_LAZY_LOOKUP(chreConfigureDebugDumpEvent);
293 if (fptr != nullptr) {
294 fptr(enable);
295 }
296 }
297
298 WEAK_SYMBOL
chreDebugDumpLog(const char * formatStr,...)299 void chreDebugDumpLog(const char *formatStr, ...) {
300 auto *fptr = CHRE_NSL_LAZY_LOOKUP(platform_chreDebugDumpVaLog);
301 if (fptr != nullptr) {
302 va_list args;
303 va_start(args, formatStr);
304 fptr(formatStr, args);
305 va_end(args);
306 }
307 }
308
309 WEAK_SYMBOL
chreSendMessageWithPermissions(void * message,size_t messageSize,uint32_t messageType,uint16_t hostEndpoint,uint32_t messagePermissions,chreMessageFreeFunction * freeCallback)310 bool chreSendMessageWithPermissions(void *message, size_t messageSize,
311 uint32_t messageType, uint16_t hostEndpoint,
312 uint32_t messagePermissions,
313 chreMessageFreeFunction *freeCallback) {
314 auto *fptr = CHRE_NSL_LAZY_LOOKUP(chreSendMessageWithPermissions);
315 if (fptr != nullptr) {
316 return fptr(message, messageSize, messageType, hostEndpoint,
317 messagePermissions, freeCallback);
318 } else {
319 return chreSendMessageToHostEndpoint(message, messageSize, messageType,
320 hostEndpoint, freeCallback);
321 }
322 }
323
324 WEAK_SYMBOL
chreUserSettingGetState(uint8_t setting)325 int8_t chreUserSettingGetState(uint8_t setting) {
326 int8_t settingState = CHRE_USER_SETTING_STATE_UNKNOWN;
327 auto *fptr = CHRE_NSL_LAZY_LOOKUP(chreUserSettingGetState);
328 if (fptr != nullptr) {
329 settingState = fptr(setting);
330 }
331 return settingState;
332 }
333
334 WEAK_SYMBOL
chreUserSettingConfigureEvents(uint8_t setting,bool enable)335 void chreUserSettingConfigureEvents(uint8_t setting, bool enable) {
336 auto *fptr = CHRE_NSL_LAZY_LOOKUP(chreUserSettingConfigureEvents);
337 if (fptr != nullptr) {
338 fptr(setting, enable);
339 }
340 }
341
342 #endif // CHRE_NANOAPP_DISABLE_BACKCOMPAT
343