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