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 {
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   constexpr uint16_t kLightBigImageEventType =
58       (CHRE_EVENT_SENSOR_DATA_EVENT_BASE + CHRE_SENSOR_TYPE_VENDOR_START + 9);
59 
60   if (*eventType == kAccelBigImageEventType) {
61     *eventType = CHRE_EVENT_SENSOR_ACCELEROMETER_DATA;
62   } else if (*eventType == kUncalAccelBigImageEventType) {
63     *eventType = CHRE_EVENT_SENSOR_UNCALIBRATED_ACCELEROMETER_DATA;
64   } else if (*eventType == kUncalGyroBigImageEventType) {
65     *eventType = CHRE_EVENT_SENSOR_UNCALIBRATED_GYROSCOPE_DATA;
66   } else if (*eventType == kUncalMagBigImageEventType) {
67     *eventType = CHRE_EVENT_SENSOR_UNCALIBRATED_GEOMAGNETIC_FIELD_DATA;
68   } else if (*eventType == kLightBigImageEventType) {
69     *eventType = CHRE_EVENT_SENSOR_LIGHT_DATA;
70   }
71 }
72 
73 /**
74  * Helper function to get the sensor type of a big-image variant of a sensor.
75  *
76  * @param sensorType The sensor type to convert from.
77  *
78  * @return The sensor type of the corresponding big-image sensor, or the input
79  *     sensor type if one does not exist.
80  */
81 uint8_t getBigImageSensorType(uint8_t sensorType) {
82   switch (sensorType) {
83     case CHRE_SENSOR_TYPE_ACCELEROMETER:
84       return CHRE_SLPI_SENSOR_TYPE_BIG_IMAGE_ACCEL;
85     case CHRE_SENSOR_TYPE_UNCALIBRATED_ACCELEROMETER:
86       return CHRE_SLPI_SENSOR_TYPE_BIG_IMAGE_UNCAL_ACCEL;
87     case CHRE_SENSOR_TYPE_UNCALIBRATED_GYROSCOPE:
88       return CHRE_SLPI_SENSOR_TYPE_BIG_IMAGE_UNCAL_GYRO;
89     case CHRE_SENSOR_TYPE_UNCALIBRATED_GEOMAGNETIC_FIELD:
90       return CHRE_SLPI_SENSOR_TYPE_BIG_IMAGE_UNCAL_MAG;
91     case CHRE_SENSOR_TYPE_LIGHT:
92       return CHRE_SLPI_SENSOR_TYPE_BIG_IMAGE_LIGHT;
93     default:
94       return sensorType;
95   }
96 }
97 
98 /**
99  * Helper function to get the handle of a big-image variant of a sensor.
100  *
101  * @param sensorHandle The sensor handle to convert from.
102  *
103  * @return The handle of the corresponding big-image sensor, or the input sensor
104  *     handle if one does not exist.
105  */
106 uint32_t getBigImageSensorHandle(uint32_t sensorHandle) {
107   Sensor *sensor =
108       EventLoopManagerSingleton::get()->getSensorRequestManager().getSensor(
109           sensorHandle);
110   uint8_t bigImageType = getBigImageSensorType(sensor->getSensorType());
111   uint32_t bigImageHandle;
112   EventLoopManagerSingleton::get()->getSensorRequestManager().getSensorHandle(
113       bigImageType, &bigImageHandle);
114   return bigImageHandle;
115 }
116 
117 /**
118  * @return true if the given event type is a bias info event.
119  */
120 bool isBiasEventType(uint16_t eventType) {
121   return eventType == CHRE_EVENT_SENSOR_ACCELEROMETER_BIAS_INFO ||
122          eventType == CHRE_EVENT_SENSOR_UNCALIBRATED_ACCELEROMETER_BIAS_INFO ||
123          eventType == CHRE_EVENT_SENSOR_GYROSCOPE_BIAS_INFO ||
124          eventType == CHRE_EVENT_SENSOR_UNCALIBRATED_GYROSCOPE_BIAS_INFO ||
125          eventType == CHRE_EVENT_SENSOR_GEOMAGNETIC_FIELD_BIAS_INFO ||
126          eventType ==
127              CHRE_EVENT_SENSOR_UNCALIBRATED_GEOMAGNETIC_FIELD_BIAS_INFO;
128 }
129 
130 }  //  anonymous namespace
131 #endif  // defined(CHRE_SLPI_SEE) && defined(CHRE_SLPI_UIMG_ENABLED)
132 
133 PlatformNanoapp::~PlatformNanoapp() {
134   closeNanoapp();
135   if (mAppBinary != nullptr) {
136     memoryFreeBigImage(mAppBinary);
137   }
138 }
139 
140 bool PlatformNanoapp::start() {
141   // Invoke the start entry point after successfully opening the app
142   if (!isUimgApp()) {
143     slpiForceBigImage();
144   }
145 
146   return openNanoapp() && mAppInfo->entryPoints.start();
147 }
148 
149 void PlatformNanoapp::handleEvent(uint32_t senderInstanceId, uint16_t eventType,
150                                   const void *eventData) {
151   if (!isUimgApp()) {
152     slpiForceBigImage();
153 
154 #if defined(CHRE_SLPI_SEE) && defined(CHRE_SLPI_UIMG_ENABLED)
155     rewriteToChreEventType(&eventType);
156 #endif  // defined(CHRE_SLPI_SEE) && defined(CHRE_SLPI_UIMG_ENABLED)
157   }
158 
159 #if defined(CHRE_SLPI_SEE) && defined(CHRE_SLPI_UIMG_ENABLED)
160   // NOTE: Since SeeCalHelper does not internally differentiate calibration
161   //       between big/micro image, convert the sensor handle to the appropriate
162   //       one when delivering a bias info event to the nanoapp.
163   chreSensorThreeAxisData bias;
164   if (eventData != nullptr && !isUimgApp() && isBiasEventType(eventType)) {
165     bias = *static_cast<const chreSensorThreeAxisData *>(eventData);
166     bias.header.sensorHandle =
167         getBigImageSensorHandle(bias.header.sensorHandle);
168     eventData = &bias;
169   }
170 #endif  // defined(CHRE_SLPI_SEE) && defined(CHRE_SLPI_UIMG_ENABLED)
171 
172   mAppInfo->entryPoints.handleEvent(senderInstanceId, eventType, eventData);
173 }
174 
175 void PlatformNanoapp::end() {
176   if (!isUimgApp()) {
177     slpiForceBigImage();
178   }
179 
180   mAppInfo->entryPoints.end();
181   closeNanoapp();
182 }
183 
184 bool PlatformNanoappBase::setAppInfo(uint64_t appId, uint32_t appVersion,
185                                      const char *appFilename) {
186   CHRE_ASSERT(!isLoaded());
187   mExpectedAppId = appId;
188   mExpectedAppVersion = appVersion;
189   size_t appFilenameLen = strlen(appFilename) + 1;
190   mAppFilename = static_cast<char *>(memoryAllocBigImage(appFilenameLen));
191 
192   bool success = false;
193   if (mAppFilename == nullptr) {
194     LOG_OOM();
195   } else {
196     memcpy(static_cast<void *>(mAppFilename), appFilename, appFilenameLen);
197     success = true;
198   }
199 
200   return success;
201 }
202 
203 bool PlatformNanoappBase::reserveBuffer(uint64_t appId, uint32_t appVersion,
204                                         size_t appBinaryLen) {
205   CHRE_ASSERT(!isLoaded());
206   bool success = false;
207   constexpr size_t kMaxAppSize = 2 * 1024 * 1024;  // 2 MiB
208 
209   if (appBinaryLen > kMaxAppSize) {
210     LOGE("Rejecting app size %zu above limit %zu", appBinaryLen, kMaxAppSize);
211   } else {
212     mAppBinary = memoryAllocBigImage(appBinaryLen);
213     if (mAppBinary == nullptr) {
214       LOGE("Couldn't allocate %zu byte buffer for nanoapp 0x%016" PRIx64,
215            appBinaryLen, appId);
216     } else {
217       mExpectedAppId = appId;
218       mExpectedAppVersion = appVersion;
219       mAppBinaryLen = appBinaryLen;
220       success = true;
221     }
222   }
223 
224   return success;
225 }
226 
227 bool PlatformNanoappBase::copyNanoappFragment(const void *buffer,
228                                               size_t bufferLen) {
229   CHRE_ASSERT(!isLoaded());
230 
231   bool success = true;
232   if (mBytesLoaded + bufferLen > mAppBinaryLen) {
233     LOGE("Overflow: cannot load %zu bytes to %zu/%zu nanoapp binary buffer",
234          bufferLen, mBytesLoaded, mAppBinaryLen);
235     success = false;
236   } else {
237     uint8_t *binaryBuffer = static_cast<uint8_t *>(mAppBinary) + mBytesLoaded;
238     memcpy(binaryBuffer, buffer, bufferLen);
239     mBytesLoaded += bufferLen;
240   }
241 
242   return success;
243 }
244 
245 void PlatformNanoappBase::loadStatic(const struct chreNslNanoappInfo *appInfo) {
246   CHRE_ASSERT(!isLoaded());
247   mIsStatic = true;
248   mAppInfo = appInfo;
249 }
250 
251 bool PlatformNanoappBase::isLoaded() const {
252   return (mIsStatic ||
253           (mAppBinary != nullptr && mBytesLoaded == mAppBinaryLen) ||
254           mDsoHandle != nullptr || mAppFilename != nullptr);
255 }
256 
257 bool PlatformNanoappBase::isUimgApp() const {
258   return mIsUimgApp;
259 }
260 
261 void PlatformNanoappBase::closeNanoapp() {
262   if (mDsoHandle != nullptr) {
263     mAppInfo = nullptr;
264     if (dlclose(mDsoHandle) != 0) {
265       LOGE("dlclose failed: %s", dlerror());
266     }
267     mDsoHandle = nullptr;
268   }
269 }
270 
271 bool PlatformNanoappBase::openNanoapp() {
272   bool success = false;
273 
274   if (mIsStatic) {
275     success = true;
276   } else if (mAppBinary != nullptr) {
277     success = openNanoappFromBuffer();
278   } else if (mAppFilename != nullptr) {
279     success = openNanoappFromFile();
280   } else {
281     CHRE_ASSERT(false);
282   }
283 
284   // Ensure any allocated memory hanging around is properly cleaned up.
285   if (!success) {
286     closeNanoapp();
287   }
288 
289   // Save this flag locally since it may be referenced while the system is in
290   // micro-image
291   if (mAppInfo != nullptr) {
292     mIsUimgApp = mAppInfo->isTcmNanoapp;
293   }
294 
295   return success;
296 }
297 
298 bool PlatformNanoappBase::openNanoappFromBuffer() {
299   CHRE_ASSERT(mAppBinary != nullptr);
300   CHRE_ASSERT_LOG(mDsoHandle == nullptr, "Re-opening nanoapp");
301 
302   // Populate a filename string (just a requirement of the dlopenbuf API)
303   constexpr size_t kMaxFilenameLen = 17;
304   char filename[kMaxFilenameLen];
305   snprintf(filename, sizeof(filename), "%016" PRIx64, mExpectedAppId);
306 
307   mDsoHandle = dlopenbuf(filename, static_cast<const char *>(mAppBinary),
308                          static_cast<int>(mAppBinaryLen), RTLD_NOW);
309   memoryFreeBigImage(mAppBinary);
310   mAppBinary = nullptr;
311 
312   return verifyNanoappInfo();
313 }
314 
315 bool PlatformNanoappBase::openNanoappFromFile() {
316   CHRE_ASSERT(mAppFilename != nullptr);
317   CHRE_ASSERT_LOG(mDsoHandle == nullptr, "Re-opening nanoapp");
318 
319   mDsoHandle = dlopen(mAppFilename, RTLD_NOW);
320   memoryFreeBigImage(mAppFilename);
321   mAppFilename = nullptr;
322 
323   return verifyNanoappInfo();
324 }
325 
326 bool PlatformNanoappBase::verifyNanoappInfo() {
327   bool success = false;
328 
329   if (mDsoHandle == nullptr) {
330     LOGE("No nanoapp info to verify: %s", dlerror());
331   } else {
332     mAppInfo = static_cast<const struct chreNslNanoappInfo *>(
333         dlsym(mDsoHandle, CHRE_NSL_DSO_NANOAPP_INFO_SYMBOL_NAME));
334     if (mAppInfo == nullptr) {
335       LOGE("Failed to find app info symbol: %s", dlerror());
336     } else {
337       success = validateAppInfo(mExpectedAppId, mExpectedAppVersion, mAppInfo);
338       if (!success) {
339         mAppInfo = nullptr;
340       } else {
341         LOGI("Successfully loaded nanoapp: %s (0x%016" PRIx64
342              ") version 0x%" PRIx32 " (%s) uimg %d system %d",
343              mAppInfo->name, mAppInfo->appId, mAppInfo->appVersion,
344              getAppVersionString(), mAppInfo->isTcmNanoapp,
345              mAppInfo->isSystemNanoapp);
346       }
347     }
348   }
349 
350   return success;
351 }
352 
353 const char *PlatformNanoappBase::getAppVersionString() const {
354   const char *versionString = "<undefined>";
355   if (mAppInfo != nullptr && mAppInfo->structMinorVersion >= 2 &&
356       mAppInfo->appVersionString != NULL) {
357     size_t appVersionStringLength = strlen(mAppInfo->appVersionString);
358 
359     size_t offset = 0;
360     for (size_t i = 0; i < appVersionStringLength; i++) {
361       size_t newOffset = i + 1;
362       if (mAppInfo->appVersionString[i] == '@' &&
363           newOffset < appVersionStringLength) {
364         offset = newOffset;
365         break;
366       }
367     }
368 
369     versionString = &mAppInfo->appVersionString[offset];
370   }
371 
372   return versionString;
373 }
374 
375 uint64_t PlatformNanoapp::getAppId() const {
376   return (mAppInfo != nullptr) ? mAppInfo->appId : mExpectedAppId;
377 }
378 
379 uint32_t PlatformNanoapp::getAppVersion() const {
380   return (mAppInfo != nullptr) ? mAppInfo->appVersion : mExpectedAppVersion;
381 }
382 
383 uint32_t PlatformNanoapp::getTargetApiVersion() const {
384   return (mAppInfo != nullptr) ? mAppInfo->targetApiVersion : 0;
385 }
386 
387 const char *PlatformNanoapp::getAppName() const {
388   return (mAppInfo != nullptr) ? mAppInfo->name : "Unknown";
389 }
390 
391 bool PlatformNanoapp::isSystemNanoapp() const {
392   // Right now, we assume that system nanoapps are always static nanoapps. Since
393   // mAppInfo can only be null either prior to loading the app (in which case
394   // this function is not expected to return a valid value anyway), or when a
395   // dynamic nanoapp is not running, "false" is the correct return value in that
396   // case.
397   return (mAppInfo != nullptr) ? mAppInfo->isSystemNanoapp : false;
398 }
399 
400 void PlatformNanoapp::logStateToBuffer(DebugDumpWrapper &debugDump) const {
401   if (mAppInfo != nullptr) {
402     debugDump.print("%s (%s) @ %s", mAppInfo->name, mAppInfo->vendor,
403                     getAppVersionString());
404   }
405 }
406 
407 }  // namespace chre
408