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 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 */
getBigImageSensorType(uint8_t sensorType)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 */
getBigImageSensorHandle(uint32_t sensorHandle)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 */
isBiasEventType(uint16_t eventType)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
~PlatformNanoapp()133 PlatformNanoapp::~PlatformNanoapp() {
134 closeNanoapp();
135 if (mAppBinary != nullptr) {
136 memoryFreeBigImage(mAppBinary);
137 }
138 }
139
start()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
handleEvent(uint32_t senderInstanceId,uint16_t eventType,const void * eventData)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
end()175 void PlatformNanoapp::end() {
176 if (!isUimgApp()) {
177 slpiForceBigImage();
178 }
179
180 mAppInfo->entryPoints.end();
181 closeNanoapp();
182 }
183
setAppInfo(uint64_t appId,uint32_t appVersion,const char * appFilename)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
reserveBuffer(uint64_t appId,uint32_t appVersion,size_t appBinaryLen)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
copyNanoappFragment(const void * buffer,size_t bufferLen)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
loadStatic(const struct chreNslNanoappInfo * appInfo)245 void PlatformNanoappBase::loadStatic(const struct chreNslNanoappInfo *appInfo) {
246 CHRE_ASSERT(!isLoaded());
247 mIsStatic = true;
248 mAppInfo = appInfo;
249 }
250
isLoaded() const251 bool PlatformNanoappBase::isLoaded() const {
252 return (mIsStatic ||
253 (mAppBinary != nullptr && mBytesLoaded == mAppBinaryLen) ||
254 mDsoHandle != nullptr || mAppFilename != nullptr);
255 }
256
isUimgApp() const257 bool PlatformNanoappBase::isUimgApp() const {
258 return mIsUimgApp;
259 }
260
closeNanoapp()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
openNanoapp()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
openNanoappFromBuffer()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
openNanoappFromFile()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
verifyNanoappInfo()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
getAppVersionString() const353 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
getAppId() const375 uint64_t PlatformNanoapp::getAppId() const {
376 return (mAppInfo != nullptr) ? mAppInfo->appId : mExpectedAppId;
377 }
378
getAppVersion() const379 uint32_t PlatformNanoapp::getAppVersion() const {
380 return (mAppInfo != nullptr) ? mAppInfo->appVersion : mExpectedAppVersion;
381 }
382
getTargetApiVersion() const383 uint32_t PlatformNanoapp::getTargetApiVersion() const {
384 return (mAppInfo != nullptr) ? mAppInfo->targetApiVersion : 0;
385 }
386
getAppName() const387 const char *PlatformNanoapp::getAppName() const {
388 return (mAppInfo != nullptr) ? mAppInfo->name : "Unknown";
389 }
390
isSystemNanoapp() const391 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
logStateToBuffer(DebugDumpWrapper & debugDump) const400 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