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