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 // Note that to avoid always polluting the include paths of nanoapps, we use
18 // symlinks under the chre_nsl_internal include path to the "real" files, e.g.
19 // chre_nsl_internal/platform/shared maps to the same files that would normally
20 // be included via chre/platform/shared
21
22 #include "chre_nsl_internal/platform/shared/nanoapp_support_lib_dso.h"
23
24 #include <chre.h>
25
26 #include "chre_nsl_internal/platform/shared/debug_dump.h"
27 #include "chre_nsl_internal/util/macros.h"
28 #include "chre_nsl_internal/util/system/napp_permissions.h"
29 #ifdef CHRE_NANOAPP_USES_WIFI
30 #include "chre_nsl_internal/util/system/wifi_util.h"
31 #endif
32
33 /**
34 * @file
35 * The Nanoapp Support Library (NSL) that gets built with nanoapps to act as an
36 * intermediary to the reference CHRE implementation. It provides hooks so the
37 * app can be registered with the system, and also provides a layer where we can
38 * implement cross-version compatibility features as needed.
39 */
40
41 namespace {
42
43 constexpr uint32_t kNanoappPermissions = 0
44 // DO NOT USE this macro outside of specific CHQTS nanoapps. This is only used
45 // to allow testing of invalid permission declarations.
46 #ifdef CHRE_TEST_NANOAPP_PERMS
47 | CHRE_TEST_NANOAPP_PERMS
48 #else
49 #ifdef CHRE_NANOAPP_USES_AUDIO
50 | static_cast<uint32_t>(chre::NanoappPermissions::CHRE_PERMS_AUDIO)
51 #endif
52 #ifdef CHRE_NANOAPP_USES_BLE
53 | static_cast<uint32_t>(chre::NanoappPermissions::CHRE_PERMS_BLE)
54 #endif
55 #ifdef CHRE_NANOAPP_USES_GNSS
56 | static_cast<uint32_t>(chre::NanoappPermissions::CHRE_PERMS_GNSS)
57 #endif
58 #ifdef CHRE_NANOAPP_USES_WIFI
59 | static_cast<uint32_t>(chre::NanoappPermissions::CHRE_PERMS_WIFI)
60 #endif
61 #ifdef CHRE_NANOAPP_USES_WWAN
62 | static_cast<uint32_t>(chre::NanoappPermissions::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) *funcPtr = nullptr; \
173 if (!lookupPerformed) { \
174 funcPtr = reinterpret_cast<decltype(funcPtr)>( \
175 dlsym(RTLD_NEXT, STRINGIFY(functionName))); \
176 lookupPerformed = true; \
177 } \
178 funcPtr; \
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 #ifdef CHRE_NANOAPP_USES_BLE
208
209 WEAK_SYMBOL
chreBleGetCapabilities()210 uint32_t chreBleGetCapabilities() {
211 auto *fptr = CHRE_NSL_LAZY_LOOKUP(chreBleGetCapabilities);
212 return (fptr != nullptr) ? fptr() : CHRE_BLE_CAPABILITIES_NONE;
213 }
214
215 WEAK_SYMBOL
chreBleGetFilterCapabilities()216 uint32_t chreBleGetFilterCapabilities() {
217 auto *fptr = CHRE_NSL_LAZY_LOOKUP(chreBleGetFilterCapabilities);
218 return (fptr != nullptr) ? fptr() : CHRE_BLE_FILTER_CAPABILITIES_NONE;
219 }
220
221 WEAK_SYMBOL
chreBleStartScanAsync(chreBleScanMode mode,uint32_t reportDelayMs,const struct chreBleScanFilter * filter)222 bool chreBleStartScanAsync(chreBleScanMode mode, uint32_t reportDelayMs,
223 const struct chreBleScanFilter *filter) {
224 auto *fptr = CHRE_NSL_LAZY_LOOKUP(chreBleStartScanAsync);
225 return (fptr != nullptr) ? fptr(mode, reportDelayMs, filter) : false;
226 }
227
228 WEAK_SYMBOL
chreBleStopScanAsync()229 bool chreBleStopScanAsync() {
230 auto *fptr = CHRE_NSL_LAZY_LOOKUP(chreBleStopScanAsync);
231 return (fptr != nullptr) ? fptr() : false;
232 }
233
234 #endif /* CHRE_NANOAPP_USES_BLE */
235
236 WEAK_SYMBOL
chreConfigureHostSleepStateEvents(bool enable)237 void chreConfigureHostSleepStateEvents(bool enable) {
238 auto *fptr = CHRE_NSL_LAZY_LOOKUP(chreConfigureHostSleepStateEvents);
239 if (fptr != nullptr) {
240 fptr(enable);
241 }
242 }
243
244 WEAK_SYMBOL
chreIsHostAwake(void)245 bool chreIsHostAwake(void) {
246 auto *fptr = CHRE_NSL_LAZY_LOOKUP(chreIsHostAwake);
247 return (fptr != nullptr) ? fptr() : false;
248 }
249
250 #ifdef CHRE_NANOAPP_USES_GNSS
251
252 WEAK_SYMBOL
chreGnssConfigurePassiveLocationListener(bool enable)253 bool chreGnssConfigurePassiveLocationListener(bool enable) {
254 auto *fptr = CHRE_NSL_LAZY_LOOKUP(chreGnssConfigurePassiveLocationListener);
255 return (fptr != nullptr) ? fptr(enable) : false;
256 }
257
258 #endif /* CHRE_NANOAPP_USES_GNSS */
259
260 #ifdef CHRE_NANOAPP_USES_WIFI
261
262 WEAK_SYMBOL
chreWifiRequestScanAsync(const struct chreWifiScanParams * params,const void * cookie)263 bool chreWifiRequestScanAsync(const struct chreWifiScanParams *params,
264 const void *cookie) {
265 auto *fptr = CHRE_NSL_LAZY_LOOKUP(chreWifiRequestScanAsync);
266
267 if (fptr == nullptr) {
268 // Should never happen
269 return false;
270 } else if (chreGetApiVersion() < CHRE_API_VERSION_1_5) {
271 const struct chreWifiScanParams legacyParams =
272 chre::translateToLegacyWifiScanParams(params);
273 return fptr(&legacyParams, cookie);
274 } else {
275 return fptr(params, cookie);
276 }
277 }
278
279 WEAK_SYMBOL
chreWifiRequestRangingAsync(const struct chreWifiRangingParams * params,const void * cookie)280 bool chreWifiRequestRangingAsync(const struct chreWifiRangingParams *params,
281 const void *cookie) {
282 auto *fptr = CHRE_NSL_LAZY_LOOKUP(chreWifiRequestRangingAsync);
283 return (fptr != nullptr) ? fptr(params, cookie) : false;
284 }
285
286 WEAK_SYMBOL
chreWifiNanRequestRangingAsync(const struct chreWifiNanRangingParams * params,const void * cookie)287 bool chreWifiNanRequestRangingAsync(
288 const struct chreWifiNanRangingParams *params, const void *cookie) {
289 auto *fptr = CHRE_NSL_LAZY_LOOKUP(chreWifiNanRequestRangingAsync);
290 return (fptr != nullptr) ? fptr(params, cookie) : false;
291 }
292
293 WEAK_SYMBOL
chreWifiNanSubscribe(struct chreWifiNanSubscribeConfig * config,const void * cookie)294 bool chreWifiNanSubscribe(struct chreWifiNanSubscribeConfig *config,
295 const void *cookie) {
296 auto *fptr = CHRE_NSL_LAZY_LOOKUP(chreWifiNanSubscribe);
297 return (fptr != nullptr) ? fptr(config, cookie) : false;
298 }
299
300 WEAK_SYMBOL
chreWifiNanSubscribeCancel(uint32_t subscriptionID)301 bool chreWifiNanSubscribeCancel(uint32_t subscriptionID) {
302 auto *fptr = CHRE_NSL_LAZY_LOOKUP(chreWifiNanSubscribeCancel);
303 return (fptr != nullptr) ? fptr(subscriptionID) : false;
304 }
305
306 #endif /* CHRE_NANOAPP_USES_WIFI */
307
308 WEAK_SYMBOL
chreSensorFind(uint8_t sensorType,uint8_t sensorIndex,uint32_t * handle)309 bool chreSensorFind(uint8_t sensorType, uint8_t sensorIndex, uint32_t *handle) {
310 auto *fptr = CHRE_NSL_LAZY_LOOKUP(chreSensorFind);
311 if (fptr != nullptr) {
312 return fptr(sensorType, sensorIndex, handle);
313 } else if (sensorIndex == 0) {
314 return chreSensorFindDefault(sensorType, handle);
315 } else {
316 return false;
317 }
318 }
319
320 WEAK_SYMBOL
chreSensorConfigureBiasEvents(uint32_t sensorHandle,bool enable)321 bool chreSensorConfigureBiasEvents(uint32_t sensorHandle, bool enable) {
322 auto *fptr = CHRE_NSL_LAZY_LOOKUP(chreSensorConfigureBiasEvents);
323 return (fptr != nullptr) ? fptr(sensorHandle, enable) : false;
324 }
325
326 WEAK_SYMBOL
chreSensorGetThreeAxisBias(uint32_t sensorHandle,struct chreSensorThreeAxisData * bias)327 bool chreSensorGetThreeAxisBias(uint32_t sensorHandle,
328 struct chreSensorThreeAxisData *bias) {
329 auto *fptr = CHRE_NSL_LAZY_LOOKUP(chreSensorGetThreeAxisBias);
330 return (fptr != nullptr) ? fptr(sensorHandle, bias) : false;
331 }
332
333 WEAK_SYMBOL
chreSensorFlushAsync(uint32_t sensorHandle,const void * cookie)334 bool chreSensorFlushAsync(uint32_t sensorHandle, const void *cookie) {
335 auto *fptr = CHRE_NSL_LAZY_LOOKUP(chreSensorFlushAsync);
336 return (fptr != nullptr) ? fptr(sensorHandle, cookie) : false;
337 }
338
339 WEAK_SYMBOL
chreConfigureDebugDumpEvent(bool enable)340 void chreConfigureDebugDumpEvent(bool enable) {
341 auto *fptr = CHRE_NSL_LAZY_LOOKUP(chreConfigureDebugDumpEvent);
342 if (fptr != nullptr) {
343 fptr(enable);
344 }
345 }
346
347 WEAK_SYMBOL
chreDebugDumpLog(const char * formatStr,...)348 void chreDebugDumpLog(const char *formatStr, ...) {
349 auto *fptr = CHRE_NSL_LAZY_LOOKUP(platform_chreDebugDumpVaLog);
350 if (fptr != nullptr) {
351 va_list args;
352 va_start(args, formatStr);
353 fptr(formatStr, args);
354 va_end(args);
355 }
356 }
357
358 WEAK_SYMBOL
chreSendMessageWithPermissions(void * message,size_t messageSize,uint32_t messageType,uint16_t hostEndpoint,uint32_t messagePermissions,chreMessageFreeFunction * freeCallback)359 bool chreSendMessageWithPermissions(void *message, size_t messageSize,
360 uint32_t messageType, uint16_t hostEndpoint,
361 uint32_t messagePermissions,
362 chreMessageFreeFunction *freeCallback) {
363 auto *fptr = CHRE_NSL_LAZY_LOOKUP(chreSendMessageWithPermissions);
364 if (fptr != nullptr) {
365 return fptr(message, messageSize, messageType, hostEndpoint,
366 messagePermissions, freeCallback);
367 } else {
368 return chreSendMessageToHostEndpoint(message, messageSize, messageType,
369 hostEndpoint, freeCallback);
370 }
371 }
372
373 WEAK_SYMBOL
chreUserSettingGetState(uint8_t setting)374 int8_t chreUserSettingGetState(uint8_t setting) {
375 int8_t settingState = CHRE_USER_SETTING_STATE_UNKNOWN;
376 auto *fptr = CHRE_NSL_LAZY_LOOKUP(chreUserSettingGetState);
377 if (fptr != nullptr) {
378 settingState = fptr(setting);
379 }
380 return settingState;
381 }
382
383 WEAK_SYMBOL
chreUserSettingConfigureEvents(uint8_t setting,bool enable)384 void chreUserSettingConfigureEvents(uint8_t setting, bool enable) {
385 auto *fptr = CHRE_NSL_LAZY_LOOKUP(chreUserSettingConfigureEvents);
386 if (fptr != nullptr) {
387 fptr(setting, enable);
388 }
389 }
390
391 WEAK_SYMBOL
chreConfigureHostEndpointNotifications(uint16_t hostEndpointId,bool enable)392 bool chreConfigureHostEndpointNotifications(uint16_t hostEndpointId,
393 bool enable) {
394 auto *fptr = CHRE_NSL_LAZY_LOOKUP(chreConfigureHostEndpointNotifications);
395 return (fptr != nullptr) ? fptr(hostEndpointId, enable) : false;
396 }
397
398 WEAK_SYMBOL
chrePublishRpcServices(struct chreNanoappRpcService * services,size_t numServices)399 bool chrePublishRpcServices(struct chreNanoappRpcService *services,
400 size_t numServices) {
401 auto *fptr = CHRE_NSL_LAZY_LOOKUP(chrePublishRpcServices);
402 return (fptr != nullptr) ? fptr(services, numServices) : false;
403 }
404
405 WEAK_SYMBOL
chreGetHostEndpointInfo(uint16_t hostEndpointId,struct chreHostEndpointInfo * info)406 bool chreGetHostEndpointInfo(uint16_t hostEndpointId,
407 struct chreHostEndpointInfo *info) {
408 auto *fptr = CHRE_NSL_LAZY_LOOKUP(chreGetHostEndpointInfo);
409 return (fptr != nullptr) ? fptr(hostEndpointId, info) : false;
410 }
411
412 #endif // CHRE_NANOAPP_DISABLE_BACKCOMPAT
413