/* * Copyright (C) 2019 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "chre/platform/platform_sensor_manager.h" #include "sns_std_sensor.pb.h" #include "stringl.h" #include #include "chre/core/event_loop_manager.h" #include "chre/core/sensor.h" #include "chre/core/sensor_type_helpers.h" #include "chre/platform/log.h" #include "chre/platform/slpi/power_control_util.h" #include "chre/platform/system_time.h" #include "chre/util/nested_data_ptr.h" #include "chre_api/chre/sensor.h" #ifdef CHREX_SENSOR_SUPPORT #include "chre/extensions/platform/slpi/see/vendor_data_types.h" #endif // CHREX_SENSOR_SUPPORT #ifdef CHRE_VARIANT_SUPPLIES_SEE_SENSORS_LIST #include "see_sensors.h" #endif // CHRE_VARIANT_SUPPLIES_SEE_SENSORS_LIST #ifndef CHRE_SEE_NUM_TEMP_SENSORS // There are usually more than one 'sensor_temperature' sensors in SEE. // Define this in the variant-specific makefile to avoid missing sensors in // sensor discovery. #error "CHRE_SEE_NUM_TEMP_SENSORS is not defined" #endif namespace chre { namespace { //! A struct to facilitate sensor discovery struct SuidAttr { sns_std_suid suid; SeeAttributes attr; }; #ifndef CHRE_VARIANT_SUPPLIES_SEE_SENSORS_LIST //! The list of SEE platform sensor data types that CHRE intends to support. //! The standardized strings are defined in sns_xxx.proto. const char *kSeeDataTypes[] = { "accel", "gyro", "mag", "pressure", "ambient_light", "proximity", #ifdef CHRE_SLPI_DEFAULT_BUILD // Both instant motion and stationary detect share the same data type. "amd", "amd", #else "motion_detect", "stationary_detect", #endif }; #endif // CHRE_VARIANT_SUPPLIES_SEE_SENSORS_LIST #ifdef CHRE_SLPI_UIMG_ENABLED #ifndef CHREX_SENSOR_SUPPORT // The current implementation uses vendor sensor type 3 to remap into accel, // with requests made through QMI instead of QSockets, as SEE does not support // micro-image batching in QCM. #error "CHRE extensions are required for micro-image SEE support" #endif // CHREX_SENSOR_SUPPORT bool isBigImageSensor(const Sensor &sensor) { return sensor.getTargetGroupMask() == NanoappGroupIds::BigImage; } bool sensorTypeSupportsBigImage(uint8_t sensorType) { return (sensorType == CHRE_SENSOR_TYPE_ACCELEROMETER || sensorType == CHRE_SENSOR_TYPE_UNCALIBRATED_ACCELEROMETER || sensorType == CHRE_SENSOR_TYPE_UNCALIBRATED_GYROSCOPE || sensorType == CHRE_SENSOR_TYPE_UNCALIBRATED_GEOMAGNETIC_FIELD || sensorType == CHRE_SENSOR_TYPE_LIGHT); } bool isBigImageSensorType(uint8_t sensorType) { return (sensorType == CHRE_SLPI_SENSOR_TYPE_BIG_IMAGE_ACCEL || sensorType == CHRE_SLPI_SENSOR_TYPE_BIG_IMAGE_UNCAL_ACCEL || sensorType == CHRE_SLPI_SENSOR_TYPE_BIG_IMAGE_UNCAL_GYRO || sensorType == CHRE_SLPI_SENSOR_TYPE_BIG_IMAGE_UNCAL_MAG || sensorType == CHRE_SLPI_SENSOR_TYPE_BIG_IMAGE_LIGHT); } uint8_t getBigImageSensorType(uint8_t sensorType) { switch (sensorType) { case CHRE_SENSOR_TYPE_ACCELEROMETER: return CHRE_SLPI_SENSOR_TYPE_BIG_IMAGE_ACCEL; case CHRE_SENSOR_TYPE_UNCALIBRATED_ACCELEROMETER: return CHRE_SLPI_SENSOR_TYPE_BIG_IMAGE_UNCAL_ACCEL; case CHRE_SENSOR_TYPE_UNCALIBRATED_GYROSCOPE: return CHRE_SLPI_SENSOR_TYPE_BIG_IMAGE_UNCAL_GYRO; case CHRE_SENSOR_TYPE_UNCALIBRATED_GEOMAGNETIC_FIELD: return CHRE_SLPI_SENSOR_TYPE_BIG_IMAGE_UNCAL_MAG; case CHRE_SENSOR_TYPE_LIGHT: return CHRE_SLPI_SENSOR_TYPE_BIG_IMAGE_LIGHT; default: return sensorType; } } /** * Obtains the micro-image sensor type given the specified sensor type. * * @param sensorType The sensor type to convert from. * @return The associated micro-image sensor type, or the input sensor type * if not associated with one */ uint8_t getUimgSensorType(uint8_t sensorType) { switch (sensorType) { case CHRE_SLPI_SENSOR_TYPE_BIG_IMAGE_ACCEL: return CHRE_SENSOR_TYPE_ACCELEROMETER; case CHRE_SLPI_SENSOR_TYPE_BIG_IMAGE_UNCAL_ACCEL: return CHRE_SENSOR_TYPE_UNCALIBRATED_ACCELEROMETER; case CHRE_SLPI_SENSOR_TYPE_BIG_IMAGE_UNCAL_GYRO: return CHRE_SENSOR_TYPE_UNCALIBRATED_GYROSCOPE; case CHRE_SLPI_SENSOR_TYPE_BIG_IMAGE_UNCAL_MAG: return CHRE_SENSOR_TYPE_UNCALIBRATED_GEOMAGNETIC_FIELD; case CHRE_SLPI_SENSOR_TYPE_BIG_IMAGE_LIGHT: return CHRE_SENSOR_TYPE_LIGHT; default: return sensorType; } } #endif // CHRE_SLPI_UIMG_ENABLED #ifndef CHRE_LOG_ONLY_NO_SENSOR /** * Callback function which will run after a delay if a required sensor is not * found. */ void crashAfterSensorNotFoundCallback(uint16_t /* eventType */, void * /* data */, void * /* extraData */) { FATAL_ERROR("Missing required sensor(s)"); } #endif void handleMissingSensor() { // Try rebooting if a sensor is missing, which might help recover from a // transient failure/race condition at startup. But to avoid endless crashes, // only do this within 15 seconds of the timeout on initializing SEE - we rely // on knowledge that getMonotonicTime() maps into QTimer here, and QTimer only // resets when the entire system is rebooted (it continues increasing after // SLPI SSR). #ifndef CHRE_LOG_ONLY_NO_SENSOR if (SystemTime::getMonotonicTime() < (kDefaultSeeWaitTimeout + Seconds(15))) { Nanoseconds delay(5 * Seconds(60).toRawNanoseconds()); // 5 minutes EventLoopManagerSingleton::get()->setDelayedCallback( SystemCallbackType::DelayedFatalError, nullptr, crashAfterSensorNotFoundCallback, delay); } #endif LOGE("Missing required sensor(s)"); } /** * Obtains the sensor type given the specified data type and whether the sensor * is runtime-calibrated or not. * * @return Whether a sensor type was found for the given data type. */ bool getSensorTypeFromDataType(const char *dataType, bool calibrated, uint8_t *sensorType, bool bigImage = false) { bool success = true; if (strcmp(dataType, "accel") == 0) { if (calibrated) { *sensorType = CHRE_SENSOR_TYPE_ACCELEROMETER; } else { *sensorType = CHRE_SENSOR_TYPE_UNCALIBRATED_ACCELEROMETER; } } else if (strcmp(dataType, "gyro") == 0) { if (calibrated) { *sensorType = CHRE_SENSOR_TYPE_GYROSCOPE; } else { *sensorType = CHRE_SENSOR_TYPE_UNCALIBRATED_GYROSCOPE; } } else if (strcmp(dataType, "mag") == 0) { if (calibrated) { *sensorType = CHRE_SENSOR_TYPE_GEOMAGNETIC_FIELD; } else { *sensorType = CHRE_SENSOR_TYPE_UNCALIBRATED_GEOMAGNETIC_FIELD; } } else if (strcmp(dataType, "pressure") == 0) { *sensorType = CHRE_SENSOR_TYPE_PRESSURE; } else if (strcmp(dataType, "ambient_light") == 0) { *sensorType = CHRE_SENSOR_TYPE_LIGHT; } else if (strcmp(dataType, "proximity") == 0) { *sensorType = CHRE_SENSOR_TYPE_PROXIMITY; } else if (strcmp(dataType, "motion_detect") == 0 || strcmp(dataType, "amd") == 0) { *sensorType = CHRE_SENSOR_TYPE_INSTANT_MOTION_DETECT; } else if (strcmp(dataType, "stationary_detect") == 0) { *sensorType = CHRE_SENSOR_TYPE_STATIONARY_DETECT; } else if (strcmp(dataType, "step_detect") == 0) { *sensorType = CHRE_SENSOR_TYPE_STEP_DETECT; } else { #ifdef CHREX_SENSOR_SUPPORT success = extension::vendorSensorTypeFromDataType(dataType, calibrated, sensorType); } #else success = false; } #endif #ifdef CHRE_SLPI_UIMG_ENABLED if (bigImage && !sensorTypeSupportsBigImage(*sensorType)) { success = false; } #endif return success; } /** * Merges a status update with an existing sampling status. */ void mergeUpdatedStatus( uint32_t sensorHandle, const SeeHelperCallbackInterface::SamplingStatusData &update, struct chreSensorSamplingStatus *mergedStatus) { Sensor *sensor = getSensorRequestManager().getSensor(sensorHandle); sensor->getSamplingStatus(mergedStatus); if (update.enabledValid) { mergedStatus->enabled = update.status.enabled; } if (update.intervalValid) { mergedStatus->interval = update.status.interval; } if (update.latencyValid) { mergedStatus->latency = update.status.latency; } } /** * Helper function to post a bias event given the bias data. * * @param sensorType The sensor type to post the event for. * @param bias The bias data. */ void postSensorBiasEvent(uint8_t sensorType, uint16_t targetGroupMask, const chreSensorThreeAxisData &bias) { uint32_t sensorHandle; if (getSensorRequestManager().getSensorHandle( sensorType, 0 /* sensorIndex */, targetGroupMask, &sensorHandle)) { auto *event = memoryAlloc(); if (event == nullptr) { LOG_OOM(); } else { *event = bias; event->header.sensorHandle = sensorHandle; getSensorRequestManager().handleBiasEvent(sensorHandle, event); } } } /** * Compares the given status updates and returns true if they are the same. * * A simple memcmp cannot be done because if a given field is not valid, then * the field may be different across updates, but doesn't indicate the update * is different. */ bool isSameStatusUpdate( const SeeHelperCallbackInterface::SamplingStatusData &status1, const SeeHelperCallbackInterface::SamplingStatusData &status2) { bool sameStatus = status1.enabledValid == status2.enabledValid; if (sameStatus && status1.enabledValid) { sameStatus &= status1.status.enabled == status2.status.enabled; } // Only check interval / latency fields if both status updates say the sensor // is enabled since CHRE doesn't care what the fields are set to if the sensor // is disabled. if (sameStatus && status1.status.enabled) { sameStatus &= status1.intervalValid == status2.intervalValid; if (sameStatus && status1.intervalValid) { sameStatus &= status1.status.interval == status2.status.interval; } sameStatus &= status1.latencyValid == status2.latencyValid; if (sameStatus && status1.latencyValid) { sameStatus &= status1.status.latency == status2.status.latency; } } return sameStatus; } /** * Constructs and initializes a sensor, and adds it to the sensor list. * * @param seeHelper SeeHelper instance to register sensor with * @param sensorType The sensor type of the sensor. * @param targetGroupMask The mask of target groups this sensor supports. * @param suid The SUID of the sensor as provided by SEE. * @param attr A reference to SeeAttrbutes. * @param sensors The sensor list. */ void addSensor(SeeHelper &seeHelper, uint8_t sensorType, uint16_t targetGroupMask, const sns_std_suid &suid, const SeeAttributes &attr, DynamicVector *sensors) { // Concatenate vendor and name with a space in between. char sensorName[kSensorNameMaxLen]; strlcpy(sensorName, attr.vendor, sizeof(sensorName)); strlcat(sensorName, " ", sizeof(sensorName)); strlcat(sensorName, attr.name, sizeof(sensorName)); // Some sensors have a max sample rate of 0 which makes ceilf return infinity // for on-change or continuous sensors when that's not the correct // minInterval. float maxSampleRate = (attr.maxSampleRate == 0.0f) ? 10 : attr.maxSampleRate; // Override one-shot sensor's minInterval to default uint64_t minInterval = SensorTypeHelpers::isOneShot(sensorType) ? CHRE_SENSOR_INTERVAL_DEFAULT : static_cast( ceilf(Seconds(1).toRawNanoseconds() / maxSampleRate)); if (!sensors->emplace_back()) { FATAL_ERROR("Failed to allocate new sensor: out of memory"); } // The sensor base class must be initialized before the main Sensor init() // can be invoked as init() is allowed to invoke base class methods. sensors->back().initBase(sensorType, minInterval, sensorName, attr.passiveRequest, targetGroupMask); sensors->back().init(); #ifdef CHRE_SLPI_UIMG_ENABLED bool resample = false; if (sensorTypeSupportsBigImage(sensorType) && targetGroupMask == NanoappGroupIds::BigImage) { // Resample big image sensors to reduce system load during sw flush. resample = true; // Use the big-image sensor type so that it's clear which samples are coming // from the big-image SEE helper. This type is mapped back to the standard // CHRE type before anything is sent to nanoapps. sensorType = getBigImageSensorType(sensorType); } #else bool resample = false; #endif bool prevRegistered; bool registered = seeHelper.registerSensor(sensorType, suid, resample, &prevRegistered); if (!registered && prevRegistered) { LOGW("SUID has been previously registered"); } else if (!registered) { FATAL_ERROR("Failed to register SUID/SensorType mapping."); } } /** * Compare SEE reported stream type attribute to the expected one. Some SEE * sensors may support more than one stream type. */ bool isStreamTypeCorrect(uint8_t sensorType, uint8_t streamType) { bool success = true; if ((SensorTypeHelpers::isContinuous(sensorType) && streamType != SNS_STD_SENSOR_STREAM_TYPE_STREAMING) || (SensorTypeHelpers::isOnChange(sensorType) && streamType != SNS_STD_SENSOR_STREAM_TYPE_ON_CHANGE) // The default SLPI build exposes instant motion / stationary sensors as // on-change, but CHRE uses them as one-shot #ifndef CHRE_SLPI_DEFAULT_BUILD || (SensorTypeHelpers::isOneShot(sensorType) && streamType != SNS_STD_SENSOR_STREAM_TYPE_SINGLE_OUTPUT) #endif ) { success = false; LOGW("Inconsistent sensor type %" PRIu8 " and stream type %" PRIu8, static_cast(sensorType), streamType); } return success; } /** * Obtains the list of SUIDs and their attributes that support the specified * data type. */ bool getSuidAndAttrs(SeeHelper &seeHelper, const char *dataType, DynamicVector *suidAttrs, uint8_t minNumSuids) { DynamicVector suids; bool success = seeHelper.findSuidSync(dataType, &suids, minNumSuids); if (!success) { LOGE("Failed to find sensor '%s'", dataType); } else { LOGV("Num of SUIDs found for '%s': %zu", dataType, suids.size()); for (const auto &suid : suids) { SeeAttributes attr; if (!seeHelper.getAttributesSync(suid, &attr)) { success = false; LOGE("Failed to get attributes of SUID 0x%" PRIx64 " %" PRIx64, suid.suid_high, suid.suid_low); } else { LOGV("%s %s, hw id %" PRId64 ", max ODR %f Hz, stream type %" PRIu8 " passive %d", attr.vendor, attr.name, attr.hwId, attr.maxSampleRate, attr.streamType, attr.passiveRequest); SuidAttr sensor = { .suid = suid, .attr = attr, }; if (!suidAttrs->push_back(sensor)) { success = false; LOG_OOM(); } } } } return success; } #ifndef CHRE_SLPI_DEFAULT_BUILD //! Check whether two sensors with the specified attrtibutes belong to the same //! sensor hardware module. bool sensorHwMatch(const SeeAttributes &attr0, const SeeAttributes &attr1) { // When HW ID is absent, its default to 0 and won't be a factor. return ((strncmp(attr0.vendor, attr1.vendor, kSeeAttrStrValLen) == 0) && (strncmp(attr0.name, attr1.name, kSeeAttrStrValLen) == 0) && (attr0.hwId == attr1.hwId)); } #endif /** * Looks up SUID(s) associated with a given sensor data type string and sensor * type enum, registers them with SeeHelper, and adds a Sensor instance to the * supplied vector for use in CHRE. When given an uncalibrated sensor type, will * also look for and add the calibrated sensor type. * * @param seeHelper SeeHelper instance to use for lookup/registration * @param temperatureSensors List of previously discovered temperature sensor * info to use for adding temp sensors associated with this sensor type * @param dataType SEE data type string * @param sensorType CHRE sensor type associated with dataType * @param targetGroupMask Group mask sensors that are added should target * @param skipAdditionalTypes if true, don't attempt to add * calibrated/temperature sensor types associated with this sensorType * @param sensors Vector to append found sensor(s) to */ void findAndAddSensorsForType(SeeHelper &seeHelper, const DynamicVector &temperatureSensors, const char *dataType, uint8_t sensorType, uint16_t targetGroupMask, bool skipAdditionalTypes, DynamicVector *sensors) { DynamicVector primarySensors; if (!getSuidAndAttrs(seeHelper, dataType, &primarySensors, 1 /* minNumSuids */)) { handleMissingSensor(); } for (const auto &primarySensor : primarySensors) { sns_std_suid suid = primarySensor.suid; SeeAttributes attr = primarySensor.attr; // Some sensors support both continuous and on-change streams. // If there are more than one SUIDs that support the data type, // choose the first one that has the expected stream type. if (isStreamTypeCorrect(sensorType, attr.streamType)) { addSensor(seeHelper, sensorType, targetGroupMask, suid, attr, sensors); if (!skipAdditionalTypes) { // Check if this sensor has a runtime-calibrated version. uint8_t calibratedType; if (getSensorTypeFromDataType(dataType, true /* calibrated */, &calibratedType) && calibratedType != sensorType) { uint16_t calTargetGroupMask = targetGroupMask; #ifdef CHRE_SLPI_UIMG_ENABLED if (!sensorTypeSupportsBigImage(calibratedType)) { // Override the target group mask if the calibrated type isn't // supported in big-image to enforce that the calibrated type is // exposed to big-image nanoapps. calTargetGroupMask = kDefaultTargetGroupMask; } #endif addSensor(seeHelper, calibratedType, calTargetGroupMask, suid, attr, sensors); } // Check if this sensor has a secondary temperature sensor. uint8_t temperatureType = PlatformSensorTypeHelpers::getTempSensorType(sensorType); if (temperatureType != CHRE_SENSOR_TYPE_INVALID) { bool tempFound = false; for (const auto &tempSensor : temperatureSensors) { sns_std_suid tempSuid = tempSensor.suid; SeeAttributes tempAttr = tempSensor.attr; #ifdef CHRE_SLPI_DEFAULT_BUILD // The default build exposes a single temp sensor to be used for // all temperature sensors that doesn't have the same attributes // as the primarySensor. if (true) { #else if (sensorHwMatch(attr, tempAttr)) { #endif LOGV("Found matching temperature sensor type"); tempFound = true; // Temp sensors aren't currently separated for big-image / uimg // so always use the default mask when adding them. constexpr uint16_t kTempGroupMask = kDefaultTargetGroupMask; addSensor(seeHelper, temperatureType, kTempGroupMask, tempSuid, tempAttr, sensors); break; } } if (!tempFound) { LOGW("Temperature sensor type %" PRIu8 " not found!", static_cast(temperatureType)); } } } break; } } } void postSamplingUpdateForSensor( Sensor *sensor, uint32_t sensorHandle, UniquePtr &&status) { // Ignore the enabled flag from status update if this is not a passive mode // supported sensor because this may cause the sampling status in CHRE to // go out of sync with reality if (!sensor->supportsPassiveMode()) { status->status.enabled = sensor->mLastReceivedSamplingStatus.status.enabled; status->enabledValid = sensor->mLastReceivedSamplingStatus.enabledValid; } if (!isSameStatusUpdate(sensor->mLastReceivedSamplingStatus, *status.get())) { sensor->mLastReceivedSamplingStatus = *status.get(); auto callback = [](uint16_t /* type */, void *data, void *extraData) { uint32_t sensorHandle = NestedDataPtr(extraData); auto *samplingStatus = static_cast(data); // This memory will be freed via releaseSamplingStatusUpdate() struct chreSensorSamplingStatus *status = memoryAlloc(); mergeUpdatedStatus(sensorHandle, *samplingStatus, status); getSensorRequestManager().handleSamplingStatusUpdate(sensorHandle, status); memoryFree(samplingStatus); }; // Schedule a deferred callback to handle sensor status change in the main // thread. EventLoopManagerSingleton::get()->deferCallback( SystemCallbackType::SensorStatusUpdate, status.release(), callback, NestedDataPtr(sensorHandle)); } } } // namespace PlatformSensorManager::~PlatformSensorManager() {} void PlatformSensorManager::init() { if (!mSeeHelper.init(this)) { FATAL_ERROR("Failed to initialize SEE helper"); } #ifdef CHRE_SLPI_UIMG_ENABLED if (!mBigImageSeeHelper.init(this, kDefaultSeeWaitTimeout, true /* skipDefaultSensorInit */)) { FATAL_ERROR("Failed to init bimg SEE helper"); } #endif // CHRE_SLPI_UIMG_ENABLED } uint16_t PlatformSensorManager::getTargetGroupId(const Nanoapp &nanoapp) const { #ifdef CHRE_SLPI_UIMG_ENABLED return (nanoapp.isUimgApp()) ? NanoappGroupIds::MicroImage : NanoappGroupIds::BigImage; #else return NanoappGroupIds::BigImage; #endif } SeeHelper &PlatformSensorManagerBase::getSeeHelperForSensor( const Sensor &sensor) { #ifdef CHRE_SLPI_UIMG_ENABLED if (isBigImageSensor(sensor)) { slpiForceBigImage(); return mBigImageSeeHelper; } else #endif { return mSeeHelper; } } #ifdef CHRE_SLPI_UIMG_ENABLED void PlatformSensorManagerBase::getBigImageSensors( DynamicVector *sensors) { CHRE_ASSERT(sensors); // Currently, just adding calibrated accel, uncal accel/gyro/mag and als as // they are the ones we know that big image nanoapps will need at a different // batching rate compared to uimg. const char *kBigImageDataTypes[] = { "accel", "gyro", "mag", "ambient_light", }; DynamicVector nullTemperatureSensorList; constexpr uint16_t kTargetGroupMask = NanoappGroupIds::BigImage; for (size_t i = 0; i < ARRAY_SIZE(kBigImageDataTypes); i++) { const char *dataType = kBigImageDataTypes[i]; // Loop through potential cal/uncal sensors. for (size_t j = 0; j < 2; j++) { uint8_t sensorType; if (getSensorTypeFromDataType(dataType, (j == 0) /* calibrated */, &sensorType), true /* bigImage */) { findAndAddSensorsForType(mBigImageSeeHelper, nullTemperatureSensorList, dataType, sensorType, kTargetGroupMask, true /* skipAdditionalTypes */, sensors); } } } } #endif // CHRE_SLPI_UIMG_ENABLED DynamicVector PlatformSensorManager::getSensors() { DynamicVector sensors; DynamicVector tempSensors; if (!getSuidAndAttrs(mSeeHelper, "sensor_temperature", &tempSensors, CHRE_SEE_NUM_TEMP_SENSORS)) { handleMissingSensor(); } #ifndef CHREX_SENSOR_SUPPORT const char *kVendorDataTypes[] = {}; #endif // CHREX_SENSOR_SUPPORT constexpr size_t kNumSeeTypes = ARRAY_SIZE(kSeeDataTypes); constexpr size_t kNumVendorTypes = ARRAY_SIZE(kVendorDataTypes); for (size_t i = 0; i < kNumSeeTypes + kNumVendorTypes; i++) { const char *dataType = (i < kNumSeeTypes) ? kSeeDataTypes[i] : kVendorDataTypes[i - kNumSeeTypes]; uint8_t sensorType; if (!getSensorTypeFromDataType(dataType, false /* calibrated */, &sensorType)) { LOGE("Unknown sensor type found for '%s'", dataType); continue; } bool skipAdditionalTypes = false; #ifdef CHRE_SLPI_DEFAULT_BUILD // Stationary and motion detect share the same dataType on the default build if (sensorType == CHRE_SENSOR_TYPE_INSTANT_MOTION_DETECT && i == kNumSeeTypes - 1) { sensorType = CHRE_SENSOR_TYPE_STATIONARY_DETECT; // Skip additional types or InstantMotion will be added to the sensor list // twice. skipAdditionalTypes = true; } #endif uint16_t targetGroupMask = kDefaultTargetGroupMask; #ifdef CHRE_SLPI_UIMG_ENABLED if (sensorTypeSupportsBigImage(sensorType)) { targetGroupMask = NanoappGroupIds::MicroImage; } #endif findAndAddSensorsForType(mSeeHelper, tempSensors, dataType, sensorType, targetGroupMask, skipAdditionalTypes, &sensors); } #ifdef CHRE_SLPI_UIMG_ENABLED getBigImageSensors(&sensors); #endif return sensors; } bool PlatformSensorManager::configureSensor(Sensor &sensor, const SensorRequest &request) { uint8_t sensorType = sensor.getSensorType(); #ifdef CHRE_SLPI_UIMG_ENABLED if (isBigImageSensor(sensor)) { sensorType = getBigImageSensorType(sensorType); } #endif SeeSensorRequest req = { .sensorType = sensorType, .enable = (request.getMode() != SensorMode::Off), .passive = sensorModeIsPassive(request.getMode()), .samplingRateHz = static_cast( kOneSecondInNanoseconds / request.getInterval().toRawNanoseconds()), // Override batch period to 0 for micro-image non-continuous sensors to // ensure one sample per batch so that nanoapps do not miss state changes. .batchPeriodUs = #ifdef CHRE_SLPI_UIMG_ENABLED (!sensor.isContinuous() && !isBigImageSensor(sensor)) ? 0 : #endif static_cast(request.getLatency().toRawNanoseconds() / kOneMicrosecondInNanoseconds), }; SeeHelper &seeHelper = getSeeHelperForSensor(sensor); bool wasInUImage = slpiInUImage(); bool success = seeHelper.makeRequest(req); // If we dropped into micro-image during that blocking call to SEE, go back // to big image. This won't happen if the calling nanoapp is a big image one, // but other code paths currently assume that we will only transition from big // image to micro-image from CHRE's perspective while it's waiting for an // event to arrive in its empty queue. // TODO: transition back to big image only when needed, at the point of // invoking a nanoapp's free event/message callback if (!wasInUImage && slpiInUImage()) { LOGD("Restoring big image operating mode"); slpiForceBigImage(); } if (success) { // TODO: remove setSamplingStatus when .latency is available in status // update from SEE. struct chreSensorSamplingStatus status; if (sensor.getSamplingStatus(&status)) { // If passive request is not supported by this SEE sensor, it won't be // dynamically enabled/disabled and its status stays the same as set here. if (!sensor.supportsPassiveMode()) { status.enabled = req.enable; } status.latency = req.batchPeriodUs * kOneMicrosecondInNanoseconds; sensor.setSamplingStatus(status); } } return success; } bool PlatformSensorManager::configureBiasEvents(const Sensor &sensor, bool enable, uint64_t /* latencyNs */) { // Big-image sensor types will be mapped into micro-image sensors so assume // using mSeeHelper is OK. SeeCalHelper *calHelper = mSeeHelper.getCalHelper(); // Make sure it's the calibrated sensor type since SeeCalHelper only deals // with calibrated types. uint8_t calibratedType = PlatformSensorTypeHelpers::toCalibratedSensorType(sensor.getSensorType()); const sns_std_suid *suid = calHelper->getCalSuidFromSensorType(calibratedType); bool success = false; if (suid != nullptr) { if (enable != calHelper->areCalUpdatesEnabled(*suid)) { success = calHelper->configureCalUpdates(*suid, enable, mSeeHelper); } else { // Return true since updates are already configured to the right state. // This can happen when configuring big-image sensors since they currently // map to the micro-image sensor type which may already be enabled. success = true; } } return success; } bool PlatformSensorManager::getThreeAxisBias( const Sensor &sensor, struct chreSensorThreeAxisData *bias) const { SeeCalHelper *calHelper = getSeeHelperForSensor(sensor).getCalHelper(); bool success = sensor.reportsBiasEvents(); if (success) { uint8_t sensorType = sensor.getSensorType(); // We use the runtime-calibrated sensor type here, per documentation // of SeeCalHelper::getBias(), but overwrite the sensorHandle to that of // the current sensor, because the calibration data itself is equivalent // for both calibrated/uncalibrated sensor types. uint8_t calSensorType = PlatformSensorTypeHelpers::toCalibratedSensorType(sensorType); if (!calHelper->getBias(calSensorType, bias)) { // Set to zero bias + unknown accuracy per CHRE API requirements. memset(bias, 0, sizeof(chreSensorThreeAxisData)); bias->header.readingCount = 1; bias->header.accuracy = CHRE_SENSOR_ACCURACY_UNKNOWN; } // Overwrite sensorHandle to match the request type. getSensorRequestManager().getSensorHandle(sensorType, 0 /* sensorIndex */, sensor.getTargetGroupMask(), &bias->header.sensorHandle); } return success; } bool PlatformSensorManager::flush(const Sensor &sensor, uint32_t *flushRequestId) { uint8_t sensorType = sensor.getSensorType(); #ifdef CHRE_SLPI_UIMG_ENABLED if (isBigImageSensor(sensor)) { sensorType = getBigImageSensorType(sensorType); } #endif return getSeeHelperForSensor(sensor).flush(sensorType); } void PlatformSensorManager::releaseSamplingStatusUpdate( struct chreSensorSamplingStatus *status) { memoryFree(status); } void PlatformSensorManager::releaseSensorDataEvent(void *data) { memoryFree(data); } void PlatformSensorManager::releaseBiasEvent(void *biasData) { memoryFree(biasData); } void PlatformSensorManagerBase::onSamplingStatusUpdate( UniquePtr &&status) { uint32_t sensorHandle; #ifdef CHRE_SLPI_UIMG_ENABLED uint16_t targetGroupMask = NanoappGroupIds::MicroImage; if (isBigImageSensorType(status->sensorType)) { status->sensorType = getUimgSensorType(status->sensorType); targetGroupMask = NanoappGroupIds::BigImage; } #else uint16_t targetGroupMask = NanoappGroupIds::BigImage; #endif getSensorRequestManager().getSensorHandle( status->sensorType, 0 /* sensorIndex */, targetGroupMask, &sensorHandle); Sensor *sensor = getSensorRequestManager().getSensor(sensorHandle); if (sensor != nullptr) { postSamplingUpdateForSensor(sensor, sensorHandle, std::move(status)); } } void PlatformSensorManagerBase::onSensorDataEvent( uint8_t sensorType, UniquePtr &&eventData) { uint32_t sensorHandle; #ifdef CHRE_SLPI_UIMG_ENABLED uint16_t targetGroupMask = NanoappGroupIds::MicroImage; if (isBigImageSensorType(sensorType)) { sensorType = getUimgSensorType(sensorType); targetGroupMask = NanoappGroupIds::BigImage; } #else uint16_t targetGroupMask = NanoappGroupIds::BigImage; #endif getSensorRequestManager().getSensorHandle(sensorType, 0 /* sensorIndex */, targetGroupMask, &sensorHandle); auto *header = reinterpret_cast(eventData.get()); header->sensorHandle = sensorHandle; getSensorRequestManager().handleSensorDataEvent(sensorHandle, eventData.release()); } void PlatformSensorManagerBase::onHostWakeSuspendEvent(bool awake) { // Host wake events are sent as soon as SEE is up so verify the event loop is // up before attempting to post the event to avoid a crash. if (EventLoopManagerSingleton::isInitialized()) { EventLoopManagerSingleton::get() ->getEventLoop() .getPowerControlManager() .onHostWakeSuspendEvent(awake); } } void PlatformSensorManagerBase::onSensorBiasEvent( uint8_t sensorType, UniquePtr &&biasData) { // A single bias update is sent for both uncal / cal types that also needs to // be sent for any big-image calibrated sensors. Currently, this requires that // we post up to 4 separate events for a single invocation of this method. uint16_t targetGroupMask; uint8_t uncalSensorType = SensorTypeHelpers::toUncalibratedSensorType(sensorType); #ifdef CHRE_SLPI_UIMG_ENABLED targetGroupMask = NanoappGroupIds::BigImage; if (sensorTypeSupportsBigImage(sensorType)) { postSensorBiasEvent(sensorType, targetGroupMask, *biasData); } if (sensorTypeSupportsBigImage(uncalSensorType)) { postSensorBiasEvent(uncalSensorType, targetGroupMask, *biasData); } #endif targetGroupMask = #ifdef CHRE_SLPI_UIMG_ENABLED NanoappGroupIds::MicroImage; #else NanoappGroupIds::BigImage; #endif postSensorBiasEvent(sensorType, targetGroupMask, *biasData); postSensorBiasEvent(uncalSensorType, targetGroupMask, *biasData); } void PlatformSensorManagerBase::onFlushCompleteEvent(uint8_t sensorType) { // Flush complete events are sent after any batch delivery so verify the // event loop is up before attempting to post the event to avoid a crash. if (EventLoopManagerSingleton::isInitialized()) { // TODO: Have SEE pass flush request IDs through the flush complete event uint32_t sensorHandle; #ifdef CHRE_SLPI_UIMG_ENABLED uint16_t targetGroupMask = NanoappGroupIds::MicroImage; if (isBigImageSensorType(sensorType)) { targetGroupMask = NanoappGroupIds::BigImage; sensorType = getUimgSensorType(sensorType); } #else uint16_t targetGroupMask = NanoappGroupIds::BigImage; #endif getSensorRequestManager().getSensorHandle(sensorType, 0 /* sensorIndex */, targetGroupMask, &sensorHandle); getSensorRequestManager().handleFlushCompleteEvent( sensorHandle, UINT32_MAX, /* invalid flush request ID */ CHRE_ERROR_NONE); } } } // namespace chre