1 /*
2  * Copyright (C) 2017 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/platform_nanoapp.h"
18 
19 #include "chre/core/event_loop_manager.h"
20 #include "chre/platform/assert.h"
21 #include "chre/platform/log.h"
22 #include "chre/platform/memory.h"
23 #include "chre/platform/shared/nanoapp_dso_util.h"
24 #include "chre/platform/shared/nanoapp_support_lib_dso.h"
25 #include "chre/platform/slpi/memory.h"
26 #include "chre/platform/slpi/power_control_util.h"
27 #include "chre/util/system/debug_dump.h"
28 #include "chre_api/chre/version.h"
29 
30 #include "dlfcn.h"
31 
32 #include <inttypes.h>
33 #include <string.h>
34 
35 namespace chre {
36 #if defined(CHRE_SLPI_SEE) && defined(CHRE_SLPI_UIMG_ENABLED)
37 namespace{
rewriteToChreEventType(uint16_t * eventType)38 void rewriteToChreEventType(uint16_t *eventType) {
39   CHRE_ASSERT(eventType);
40 
41   // HACK: as SEE does not support software batching in uimg via
42   // QCM/uQSockets, we rewrite requests for accel and uncal accel/gyro/mag
43   // from big image nanoapps to respective vendor types in
44   // chreSensorFindDefault(), which is implemented as sensor data routed
45   // through CM/QMI and supports batching. Rewrite sensor data arriving
46   // on this event type to the vanilla sensor event type so that this appears
47   // transparent to the nanoapp.
48   // TODO(P2-5673a9): work with QC to determine a better long-term solution
49   constexpr uint16_t kAccelBigImageEventType =
50       (CHRE_EVENT_SENSOR_DATA_EVENT_BASE + CHRE_SENSOR_TYPE_VENDOR_START + 3);
51   constexpr uint16_t kUncalAccelBigImageEventType =
52       (CHRE_EVENT_SENSOR_DATA_EVENT_BASE + CHRE_SENSOR_TYPE_VENDOR_START + 6);
53   constexpr uint16_t kUncalGyroBigImageEventType =
54       (CHRE_EVENT_SENSOR_DATA_EVENT_BASE + CHRE_SENSOR_TYPE_VENDOR_START + 7);
55   constexpr uint16_t kUncalMagBigImageEventType =
56       (CHRE_EVENT_SENSOR_DATA_EVENT_BASE + CHRE_SENSOR_TYPE_VENDOR_START + 8);
57 
58   if (*eventType == kAccelBigImageEventType) {
59     *eventType = CHRE_EVENT_SENSOR_ACCELEROMETER_DATA;
60   } else if (*eventType == kUncalAccelBigImageEventType) {
61     *eventType = CHRE_EVENT_SENSOR_UNCALIBRATED_ACCELEROMETER_DATA;
62   } else if (*eventType == kUncalGyroBigImageEventType) {
63     *eventType = CHRE_EVENT_SENSOR_UNCALIBRATED_GYROSCOPE_DATA;
64   } else if (*eventType == kUncalMagBigImageEventType) {
65     *eventType = CHRE_EVENT_SENSOR_UNCALIBRATED_GEOMAGNETIC_FIELD_DATA;
66   }
67 }
68 
69 /**
70  * Helper function to get the sensor type of a big-image variant of a sensor.
71  *
72  * @param sensorType The sensor type to convert from.
73  *
74  * @return The sensor type of the corresponding big-image sensor, or the input
75  *     sensor type if one does not exist.
76  */
getBigImageSensorType(SensorType sensorType)77 SensorType getBigImageSensorType(SensorType sensorType) {
78   switch (sensorType) {
79     case SensorType::Accelerometer:
80       return SensorType::VendorType3;
81     case SensorType::UncalibratedAccelerometer:
82       return SensorType::VendorType6;
83     case SensorType::UncalibratedGyroscope:
84       return SensorType::VendorType7;
85     case SensorType::UncalibratedGeomagneticField:
86       return SensorType::VendorType8;
87     default:
88       return sensorType;
89   }
90 }
91 
92 /**
93  * Helper function to get the handle of a big-image variant of a sensor.
94  *
95  * @param sensorHandle The sensor handle to convert from.
96  *
97  * @return The handle of the corresponding big-image sensor, or the input sensor
98  *     handle if one does not exist.
99  */
getBigImageSensorHandle(uint32_t sensorHandle)100 uint32_t getBigImageSensorHandle(uint32_t sensorHandle) {
101   SensorType sensorType = getSensorTypeFromSensorHandle(sensorHandle);
102   sensorType = getBigImageSensorType(sensorType);
103   return getSensorHandleFromSensorType(sensorType);
104 }
105 
106 /**
107  * @return true if the given event type is a bias info event.
108  */
isBiasEventType(uint16_t eventType)109 bool isBiasEventType(uint16_t eventType) {
110   return eventType == CHRE_EVENT_SENSOR_ACCELEROMETER_BIAS_INFO ||
111       eventType == CHRE_EVENT_SENSOR_UNCALIBRATED_ACCELEROMETER_BIAS_INFO ||
112       eventType == CHRE_EVENT_SENSOR_GYROSCOPE_BIAS_INFO ||
113       eventType == CHRE_EVENT_SENSOR_UNCALIBRATED_GYROSCOPE_BIAS_INFO ||
114       eventType == CHRE_EVENT_SENSOR_GEOMAGNETIC_FIELD_BIAS_INFO ||
115       eventType == CHRE_EVENT_SENSOR_UNCALIBRATED_GEOMAGNETIC_FIELD_BIAS_INFO;
116 }
117 
118 } //  anonymous namespace
119 #endif  // defined(CHRE_SLPI_SEE) && defined(CHRE_SLPI_UIMG_ENABLED)
120 
~PlatformNanoapp()121 PlatformNanoapp::~PlatformNanoapp() {
122   closeNanoapp();
123   if (mAppBinary != nullptr) {
124     memoryFreeBigImage(mAppBinary);
125   }
126 }
127 
start()128 bool PlatformNanoapp::start() {
129   // Invoke the start entry point after successfully opening the app
130   if (!isUimgApp()) {
131     slpiForceBigImage();
132   }
133 
134   return openNanoapp() && mAppInfo->entryPoints.start();
135 }
136 
handleEvent(uint32_t senderInstanceId,uint16_t eventType,const void * eventData)137 void PlatformNanoapp::handleEvent(uint32_t senderInstanceId,
138                                   uint16_t eventType,
139                                   const void *eventData) {
140   if (!isUimgApp()) {
141     slpiForceBigImage();
142 
143 #if defined(CHRE_SLPI_SEE) && defined(CHRE_SLPI_UIMG_ENABLED)
144     rewriteToChreEventType(&eventType);
145 #endif  // defined(CHRE_SLPI_SEE) && defined(CHRE_SLPI_UIMG_ENABLED)
146   }
147 
148 #if defined(CHRE_SLPI_SEE) && defined(CHRE_SLPI_UIMG_ENABLED)
149   // NOTE: Since SeeCalHelper does not internally differentiate calibration
150   //       between big/micro image, convert the sensor handle to the appropriate
151   //       one when delivering a bias info event to the nanoapp.
152   chreSensorThreeAxisData bias;
153   if (eventData != nullptr && !isUimgApp() && isBiasEventType(eventType)) {
154     bias = *static_cast<const chreSensorThreeAxisData *>(eventData);
155     bias.header.sensorHandle =
156         getBigImageSensorHandle(bias.header.sensorHandle);
157     eventData = &bias;
158   }
159 #endif  // defined(CHRE_SLPI_SEE) && defined(CHRE_SLPI_UIMG_ENABLED)
160 
161   mAppInfo->entryPoints.handleEvent(senderInstanceId, eventType, eventData);
162 }
163 
end()164 void PlatformNanoapp::end() {
165   if (!isUimgApp()) {
166     slpiForceBigImage();
167   }
168 
169   mAppInfo->entryPoints.end();
170   closeNanoapp();
171 }
172 
setAppInfo(uint64_t appId,uint32_t appVersion,const char * appFilename)173 bool PlatformNanoappBase::setAppInfo(
174     uint64_t appId, uint32_t appVersion, const char *appFilename) {
175   CHRE_ASSERT(!isLoaded());
176   mExpectedAppId = appId;
177   mExpectedAppVersion = appVersion;
178   size_t appFilenameLen = strlen(appFilename) + 1;
179   mAppFilename = static_cast<char *>(memoryAllocBigImage(appFilenameLen));
180 
181   bool success = false;
182   if (mAppFilename == nullptr) {
183     LOG_OOM();
184   } else {
185     memcpy(static_cast<void *>(mAppFilename), appFilename, appFilenameLen);
186     success = true;
187   }
188 
189   return success;
190 }
191 
reserveBuffer(uint64_t appId,uint32_t appVersion,size_t appBinaryLen)192 bool PlatformNanoappBase::reserveBuffer(
193     uint64_t appId, uint32_t appVersion, size_t appBinaryLen) {
194   CHRE_ASSERT(!isLoaded());
195   bool success = false;
196   constexpr size_t kMaxAppSize = 2 * 1024 * 1024;  // 2 MiB
197 
198   if (appBinaryLen > kMaxAppSize) {
199     LOGE("Rejecting app size %zu above limit %zu", appBinaryLen, kMaxAppSize);
200   } else {
201     mAppBinary = memoryAllocBigImage(appBinaryLen);
202     if (mAppBinary == nullptr) {
203       LOGE("Couldn't allocate %zu byte buffer for nanoapp 0x%016" PRIx64,
204            appBinaryLen, appId);
205     } else {
206       mExpectedAppId = appId;
207       mExpectedAppVersion = appVersion;
208       mAppBinaryLen = appBinaryLen;
209       success = true;
210     }
211   }
212 
213   return success;
214 }
215 
copyNanoappFragment(const void * buffer,size_t bufferLen)216 bool PlatformNanoappBase::copyNanoappFragment(
217     const void *buffer, size_t bufferLen) {
218   CHRE_ASSERT(!isLoaded());
219 
220   bool success = true;
221   if (mBytesLoaded + bufferLen > mAppBinaryLen) {
222     LOGE("Overflow: cannot load %zu bytes to %zu/%zu nanoapp binary buffer",
223          bufferLen, mBytesLoaded, mAppBinaryLen);
224     success = false;
225   } else {
226     uint8_t *binaryBuffer = static_cast<uint8_t *>(mAppBinary) + mBytesLoaded;
227     memcpy(binaryBuffer, buffer, bufferLen);
228     mBytesLoaded += bufferLen;
229   }
230 
231   return success;
232 }
233 
loadStatic(const struct chreNslNanoappInfo * appInfo)234 void PlatformNanoappBase::loadStatic(const struct chreNslNanoappInfo *appInfo) {
235   CHRE_ASSERT(!isLoaded());
236   mIsStatic = true;
237   mAppInfo = appInfo;
238 }
239 
isLoaded() const240 bool PlatformNanoappBase::isLoaded() const {
241   return (mIsStatic || (mAppBinary != nullptr && mBytesLoaded == mAppBinaryLen)
242           || mDsoHandle != nullptr || mAppFilename != nullptr);
243 }
244 
isUimgApp() const245 bool PlatformNanoappBase::isUimgApp() const {
246   return mIsUimgApp;
247 }
248 
closeNanoapp()249 void PlatformNanoappBase::closeNanoapp() {
250   if (mDsoHandle != nullptr) {
251     mAppInfo = nullptr;
252     if (dlclose(mDsoHandle) != 0) {
253       LOGE("dlclose failed: %s", dlerror());
254     }
255     mDsoHandle = nullptr;
256   }
257 }
258 
openNanoapp()259 bool PlatformNanoappBase::openNanoapp() {
260   bool success = false;
261 
262   if (mIsStatic) {
263     success = true;
264   } else if (mAppBinary != nullptr) {
265     success = openNanoappFromBuffer();
266   } else if (mAppFilename != nullptr) {
267     success = openNanoappFromFile();
268   } else {
269     CHRE_ASSERT(false);
270   }
271 
272   // Ensure any allocated memory hanging around is properly cleaned up.
273   if (!success) {
274     closeNanoapp();
275   }
276 
277   // Save this flag locally since it may be referenced while the system is in
278   // micro-image
279   if (mAppInfo != nullptr) {
280     mIsUimgApp = mAppInfo->isTcmNanoapp;
281   }
282 
283   return success;
284 }
285 
openNanoappFromBuffer()286 bool PlatformNanoappBase::openNanoappFromBuffer() {
287   CHRE_ASSERT(mAppBinary != nullptr);
288   CHRE_ASSERT_LOG(mDsoHandle == nullptr, "Re-opening nanoapp");
289 
290   // Populate a filename string (just a requirement of the dlopenbuf API)
291   constexpr size_t kMaxFilenameLen = 17;
292   char filename[kMaxFilenameLen];
293   snprintf(filename, sizeof(filename), "%016" PRIx64, mExpectedAppId);
294 
295   mDsoHandle = dlopenbuf(
296       filename, static_cast<const char *>(mAppBinary),
297       static_cast<int>(mAppBinaryLen), RTLD_NOW);
298   memoryFreeBigImage(mAppBinary);
299   mAppBinary = nullptr;
300 
301   return verifyNanoappInfo();
302 }
303 
openNanoappFromFile()304 bool PlatformNanoappBase::openNanoappFromFile() {
305   CHRE_ASSERT(mAppFilename != nullptr);
306   CHRE_ASSERT_LOG(mDsoHandle == nullptr, "Re-opening nanoapp");
307 
308   mDsoHandle = dlopen(mAppFilename, RTLD_NOW);
309   memoryFreeBigImage(mAppFilename);
310   mAppFilename = nullptr;
311 
312   return verifyNanoappInfo();
313 }
314 
verifyNanoappInfo()315 bool PlatformNanoappBase::verifyNanoappInfo() {
316   bool success = false;
317 
318   if (mDsoHandle == nullptr) {
319     LOGE("No nanoapp info to verify: %s", dlerror());
320   } else {
321     mAppInfo = static_cast<const struct chreNslNanoappInfo *>(
322         dlsym(mDsoHandle, CHRE_NSL_DSO_NANOAPP_INFO_SYMBOL_NAME));
323     if (mAppInfo == nullptr) {
324       LOGE("Failed to find app info symbol: %s", dlerror());
325     } else {
326       success = validateAppInfo(mExpectedAppId, mExpectedAppVersion, mAppInfo);
327       if (!success) {
328         mAppInfo = nullptr;
329       } else {
330         LOGI("Successfully loaded nanoapp: %s (0x%016" PRIx64 ") version 0x%"
331              PRIx32 " (%s) uimg %d system %d", mAppInfo->name, mAppInfo->appId,
332              mAppInfo->appVersion, getAppVersionString(),
333              mAppInfo->isTcmNanoapp, mAppInfo->isSystemNanoapp);
334       }
335     }
336   }
337 
338   return success;
339 }
340 
getAppVersionString() const341 const char *PlatformNanoappBase::getAppVersionString() const {
342   const char *versionString = "<undefined>";
343   if (mAppInfo != nullptr && mAppInfo->structMinorVersion >= 2
344       && mAppInfo->appVersionString != NULL) {
345     size_t appVersionStringLength = strlen(mAppInfo->appVersionString);
346 
347     size_t offset = 0;
348     for (size_t i = 0; i < appVersionStringLength; i++) {
349       size_t newOffset = i + 1;
350       if (mAppInfo->appVersionString[i] == '@'
351           && newOffset < appVersionStringLength) {
352         offset = newOffset;
353         break;
354       }
355     }
356 
357     versionString = &mAppInfo->appVersionString[offset];
358   }
359 
360   return versionString;
361 }
362 
getAppId() const363 uint64_t PlatformNanoapp::getAppId() const {
364   return (mAppInfo != nullptr) ? mAppInfo->appId : mExpectedAppId;
365 }
366 
getAppVersion() const367 uint32_t PlatformNanoapp::getAppVersion() const {
368   return (mAppInfo != nullptr) ? mAppInfo->appVersion : mExpectedAppVersion;
369 }
370 
getTargetApiVersion() const371 uint32_t PlatformNanoapp::getTargetApiVersion() const {
372   return (mAppInfo != nullptr) ? mAppInfo->targetApiVersion : 0;
373 }
374 
isSystemNanoapp() const375 bool PlatformNanoapp::isSystemNanoapp() const {
376   // Right now, we assume that system nanoapps are always static nanoapps. Since
377   // mAppInfo can only be null either prior to loading the app (in which case
378   // this function is not expected to return a valid value anyway), or when a
379   // dynamic nanoapp is not running, "false" is the correct return value in that
380   // case.
381   return (mAppInfo != nullptr) ? mAppInfo->isSystemNanoapp : false;
382 }
383 
logStateToBuffer(char * buffer,size_t * bufferPos,size_t bufferSize) const384 void PlatformNanoapp::logStateToBuffer(char *buffer, size_t *bufferPos,
385                                        size_t bufferSize) const {
386   if (mAppInfo != nullptr) {
387     debugDumpPrint(buffer, bufferPos, bufferSize,
388                    " %s: vendor=\"%s\" commit=\"%s\"",
389                    mAppInfo->name, mAppInfo->vendor, getAppVersionString());
390   }
391 }
392 
393 }  // namespace chre
394