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