/* * Copyright (C) 2017 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.h" #include "sns_std_sensor.pb.h" #include "stringl.h" #include #include "chre_api/chre/sensor.h" #include "chre/core/event_loop_manager.h" #include "chre/core/sensor.h" #include "chre/platform/assert.h" #include "chre/platform/fatal_error.h" #include "chre/platform/log.h" #include "chre/platform/shared/platform_sensor_util.h" #include "chre/platform/slpi/power_control_util.h" #include "chre/platform/slpi/see/see_client.h" #include "chre/platform/system_time.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 { #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 isBigImageSensorType(SensorType sensorType) { return (sensorType == SensorType::VendorType3 // accel || sensorType == SensorType::VendorType6 // uncal accel || sensorType == SensorType::VendorType7 // uncal gyro || sensorType == SensorType::VendorType8); // uncal mag } /** * Obtains the big-image sensor type given the specified data type and whether * the sensor is runtime-calibrated or not. */ SensorType getBigImageSensorTypeFromDataType(const char *dataType, bool calibrated) { SensorType sensorType = SensorType::Unknown; if (strcmp(dataType, "accel") == 0) { if (calibrated) { sensorType = SensorType::VendorType3; } else { sensorType = SensorType::VendorType6; } } else if (strcmp(dataType, "gyro") == 0 && !calibrated) { sensorType = SensorType::VendorType7; } else if (strcmp(dataType, "mag") == 0 && !calibrated) { sensorType = SensorType::VendorType8; } 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 */ SensorType getUimgSensorType(SensorType sensorType) { switch (sensorType) { case SensorType::VendorType3: return SensorType::Accelerometer; case SensorType::VendorType6: return SensorType::UncalibratedAccelerometer; case SensorType::VendorType7: return SensorType::UncalibratedGyroscope; case SensorType::VendorType8: return SensorType::UncalibratedGeomagneticField; default: return sensorType; } } #endif // CHRE_SLPI_UIMG_ENABLED //! A class that implements SeeHelperCallbackInterface. class SeeHelperCallback : public SeeHelperCallbackInterface { void onSamplingStatusUpdate( UniquePtr&& status) override; void onSensorDataEvent( SensorType sensorType, UniquePtr&& eventData) override; void onHostWakeSuspendEvent(bool awake) override; void onSensorBiasEvent(UniquePtr&& biasData) override; void onFlushCompleteEvent(SensorType sensorType) override; }; //! 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 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))) { FATAL_ERROR("Missing required sensor(s)"); } else #endif { LOGE("Missing required sensor(s)"); } } /** * Obtains the sensor type given the specified data type and whether the sensor * is runtime-calibrated or not. */ SensorType getSensorTypeFromDataType(const char *dataType, bool calibrated) { SensorType sensorType; if (strcmp(dataType, "accel") == 0) { if (calibrated) { sensorType = SensorType::Accelerometer; } else { sensorType = SensorType::UncalibratedAccelerometer; } } else if (strcmp(dataType, "gyro") == 0) { if (calibrated) { sensorType = SensorType::Gyroscope; } else { sensorType = SensorType::UncalibratedGyroscope; } } else if (strcmp(dataType, "mag") == 0) { if (calibrated) { sensorType = SensorType::GeomagneticField; } else { sensorType = SensorType::UncalibratedGeomagneticField; } } else if (strcmp(dataType, "pressure") == 0) { sensorType = SensorType::Pressure; } else if (strcmp(dataType, "ambient_light") == 0) { sensorType = SensorType::Light; } else if (strcmp(dataType, "proximity") == 0) { sensorType = SensorType::Proximity; } else if (strcmp(dataType, "motion_detect") == 0 || strcmp(dataType, "amd") == 0) { sensorType = SensorType::InstantMotion; } else if (strcmp(dataType, "stationary_detect") == 0) { sensorType = SensorType::StationaryDetect; } else if (strcmp(dataType, "step_detect") == 0) { sensorType = SensorType::StepDetect; #ifdef CHREX_SENSOR_SUPPORT } else if (strcmp(dataType, kVendorDataTypes[0]) == 0) { sensorType = SensorType::VendorType0; #endif // CHREX_SENSOR_SUPPORT } else { sensorType = SensorType::Unknown; } return sensorType; } /** * Posts a CHRE_EVENT_SENSOR_SAMPLING_CHANGE event to the specified Nanoapp. * * @param instaceId The instance ID of the nanoapp with an open request. * @param sensorHandle The handle of the sensor. * @param status A reference of the sampling status to be posted. */ void postSamplingStatusEvent(uint32_t instanceId, uint32_t sensorHandle, const struct chreSensorSamplingStatus& status) { auto *event = memoryAlloc(); if (event == nullptr) { LOG_OOM(); } else { event->sensorHandle = sensorHandle; event->status = status; EventLoopManagerSingleton::get()->getEventLoop().postEventOrDie( CHRE_EVENT_SENSOR_SAMPLING_CHANGE, event, freeEventDataCallback, instanceId); } } /** * 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(SensorType sensorType, const chreSensorThreeAxisData& bias) { uint16_t eventType; if (getSensorBiasEventType(sensorType, &eventType)) { auto *event = memoryAlloc(); if (event == nullptr) { LOG_OOM(); } else { *event = bias; event->header.sensorHandle = getSensorHandleFromSensorType(sensorType); EventLoopManagerSingleton::get()->getEventLoop().postEventOrDie( eventType, event, freeEventDataCallback); } } } /** * Updates the sampling status. * * This should only be called when the new SamplingStatusData is different * from the most recently processed SamplingStatusData to avoid duplicate * updates being posted to nanoapps. */ void updateSamplingStatus( const SeeHelperCallbackInterface::SamplingStatusData& update) { Sensor *sensor = EventLoopManagerSingleton::get()->getSensorRequestManager() .getSensor(update.sensorType); struct chreSensorSamplingStatus newStatus; if (sensor != nullptr && !sensorTypeIsOneShot(update.sensorType) && sensor->getSamplingStatus(&newStatus)) { if (update.enabledValid) { newStatus.enabled = update.status.enabled; } if (update.intervalValid) { newStatus.interval = update.status.interval; } if (update.latencyValid) { newStatus.latency = update.status.latency; } sensor->setSamplingStatus(newStatus); // Only post to Nanoapps with an open request. uint32_t sensorHandle = getSensorHandleFromSensorType(update.sensorType); const DynamicVector& requests = EventLoopManagerSingleton::get()->getSensorRequestManager() .getRequests(update.sensorType); for (const auto& req : requests) { postSamplingStatusEvent(req.getInstanceId(), sensorHandle, newStatus); } } } /** * 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; } void SeeHelperCallback::onSamplingStatusUpdate( UniquePtr&& status) { Sensor *sensor = EventLoopManagerSingleton::get()->getSensorRequestManager() .getSensor(status->sensorType); // TODO: Once the latency field is actually filled in by SEE, modify this // logic to avoid reacting if the latency and interval of the sensor are // updated separately, but contain the same info as before. if (sensor != nullptr && !isSameStatusUpdate(sensor->mLastReceivedSamplingStatus, *status.get())) { sensor->mLastReceivedSamplingStatus = *status.get(); auto callback = [](uint16_t /* type */, void *data) { auto cbData = UniquePtr( static_cast(data)); updateSamplingStatus(*cbData); }; // Schedule a deferred callback to handle sensor status change in the main // thread. EventLoopManagerSingleton::get()->deferCallback( SystemCallbackType::SensorStatusUpdate, status.release(), callback); } } void SeeHelperCallback::onSensorDataEvent( SensorType sensorType, UniquePtr&& eventData) { // Schedule a deferred callback to update on-change sensor's last event in // the main thread. if (sensorTypeIsOnChange(sensorType)) { updateLastEvent(sensorType, eventData.get()); } EventLoopManagerSingleton::get()->getSensorRequestManager().handleSensorEvent( sensorType, eventData.get()); eventData.release(); } void SeeHelperCallback::onHostWakeSuspendEvent(bool awake) { if (EventLoopManagerSingleton::isInitialized()) { EventLoopManagerSingleton::get()->getEventLoop() .getPowerControlManager().onHostWakeSuspendEvent(awake); } } void SeeHelperCallback::onSensorBiasEvent( UniquePtr&& biasData) { SensorType sensorType = getSensorTypeFromSensorHandle( biasData->header.sensorHandle); uint16_t eventType; if (!sensorTypeIsCalibrated(sensorType) || !getSensorBiasEventType(sensorType, &eventType)) { LOGE("Received bias event for unsupported sensor type %" PRIu8, sensorType); } else { // Posts a newly allocated event for the uncalibrated type postSensorBiasEvent(toUncalibratedSensorType(sensorType), *biasData.get()); EventLoopManagerSingleton::get()->getEventLoop().postEventOrDie( eventType, biasData.release(), freeEventDataCallback); } } void SeeHelperCallback::onFlushCompleteEvent(SensorType sensorType) { if (EventLoopManagerSingleton::isInitialized()) { EventLoopManagerSingleton::get()->getSensorRequestManager() .handleFlushCompleteEvent(CHRE_ERROR_NONE, sensorType); } } /** * Allocates memory and specifies the memory size for an on-change sensor to * store its last data event. * * @param sensorType The sensorType of this sensor. * @param eventSize A non-null pointer to indicate the memory size allocated. * @return Pointer to the memory allocated. */ ChreSensorData *allocateLastEvent(SensorType sensorType, size_t *eventSize) { CHRE_ASSERT(eventSize); *eventSize = 0; ChreSensorData *event = nullptr; if (sensorTypeIsOnChange(sensorType)) { SensorSampleType sampleType = getSensorSampleTypeFromSensorType(sensorType); switch (sampleType) { case SensorSampleType::ThreeAxis: *eventSize = sizeof(chreSensorThreeAxisData); break; case SensorSampleType::Float: *eventSize = sizeof(chreSensorFloatData); break; case SensorSampleType::Byte: *eventSize = sizeof(chreSensorByteData); break; case SensorSampleType::Occurrence: *eventSize = sizeof(chreSensorOccurrenceData); break; default: CHRE_ASSERT_LOG(false, "Unhandled sample type"); break; } event = static_cast(memoryAlloc(*eventSize)); if (event == nullptr) { *eventSize = 0; FATAL_ERROR("Failed to allocate last event memory for SensorType %" PRIu8, static_cast(sensorType)); } } return event; } /** * Constructs and initializes a sensor, and adds it to the sensor list. * * @param seeHelper SeeHelper instance to register sensor with * @param suid The SUID of the sensor as provided by SEE. * @param sensorType The sensor type of the sensor. * @param calibrated Whether the sensor is runtime-calibrated or not. * @param attr A reference to SeeAttrbutes. * @param sensor The sensor list. */ void addSensor(SeeHelper& seeHelper, SensorType sensorType, 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 = sensorTypeIsOneShot(sensorType) ? CHRE_SENSOR_INTERVAL_DEFAULT : static_cast( ceilf(Seconds(1).toRawNanoseconds() / maxSampleRate)); // Allocates memory for on-change sensor's last event. size_t lastEventSize; ChreSensorData *lastEvent = allocateLastEvent(sensorType, &lastEventSize); // Constructs and initializes PlatformSensorBase. Sensor sensor; sensor.initBase(sensorType, minInterval, sensorName, lastEvent, lastEventSize, attr.passiveRequest); if (!sensors->push_back(std::move(sensor))) { FATAL_ERROR("Failed to allocate new sensor: out of memory"); } // Resample big image sensors to reduce system load during sw flush. #ifdef CHRE_SLPI_UIMG_ENABLED bool resample = isBigImageSensorType(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(SensorType sensorType, uint8_t streamType) { bool success = true; if ((sensorTypeIsContinuous(sensorType) && streamType != SNS_STD_SENSOR_STREAM_TYPE_STREAMING) || (sensorTypeIsOnChange(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 || (sensorTypeIsOneShot(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 { LOGD("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 { LOGI("%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, it's 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 enum associated with dataType * @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, SensorType sensorType, 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, suid, attr, sensors); if (!skipAdditionalTypes) { // Check if this sensor has a runtime-calibrated version. SensorType calibratedType = getSensorTypeFromDataType( dataType, true /* calibrated */); if (calibratedType != sensorType) { addSensor(seeHelper, calibratedType, suid, attr, sensors); } // Check if this sensor has a secondary temperature sensor. SensorType temperatureType = getTempSensorType(sensorType); if (temperatureType != SensorType::Unknown) { 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 LOGD("Found matching temperature sensor type"); tempFound = true; addSensor(seeHelper, temperatureType, tempSuid, tempAttr, sensors); break; } } if (!tempFound) { LOGW("Temperature sensor type %" PRIu8 " not found!", static_cast(temperatureType)); } } } break; } } } #ifdef CHRE_SLPI_UIMG_ENABLED /** * Registers alternate sensor(s) to be used separately by big image nanoapps. */ void getBigImageSensors(DynamicVector *sensors) { CHRE_ASSERT(sensors); // Currently, just adding calibrated accel and uncal accel/gyro/mag 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", }; SeeHelper& seeHelper = *getBigImageSeeHelper(); DynamicVector nullTemperatureSensorList; 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++) { SensorType sensorType = getBigImageSensorTypeFromDataType( dataType, (j == 0) /* calibrated */); if (sensorType != SensorType::Unknown) { findAndAddSensorsForType( seeHelper, nullTemperatureSensorList, dataType, sensorType, true /* skipAdditionalTypes */, sensors); } } } } #endif // CHRE_SLPI_UIMG_ENABLED /** * Helper function to retrieve the SeeHelper for a given sensor type. * @param sensorType the sensor type * @return the appropriate (bimg or uimg) SeeHelper */ SeeHelper *getSeeHelperForSensorType(SensorType sensorType) { SeeHelper *seeHelper = getSeeHelper(); #ifdef CHRE_SLPI_UIMG_ENABLED if (isBigImageSensorType(sensorType)) { seeHelper = getBigImageSeeHelper(); slpiForceBigImage(); } #endif return seeHelper; } } // anonymous namespace PlatformSensor::~PlatformSensor() { if (mLastEvent != nullptr) { LOGD("Releasing lastEvent: sensor %s, size %zu", getSensorTypeName(getSensorType()), mLastEventSize); memoryFree(mLastEvent); } } void PlatformSensor::init() { SeeHelperSingleton::init(); static SeeHelperCallback seeHelperCallback; if (!getSeeHelper()->init(&seeHelperCallback)) { FATAL_ERROR("Failed to initialize SEE helper"); } #ifdef CHRE_SLPI_UIMG_ENABLED BigImageSeeHelperSingleton::init(getSeeHelper()->getCalHelper()); if (!getBigImageSeeHelper()->init(&seeHelperCallback, kDefaultSeeWaitTimeout, true /* skipDefaultSensorInit */)) { FATAL_ERROR("Failed to init bimg SEE helper"); } #endif // CHRE_SLPI_UIMG_ENABLED } void PlatformSensor::deinit() { #ifdef CHRE_SLPI_UIMG_ENABLED BigImageSeeHelperSingleton::deinit(); #endif SeeHelperSingleton::deinit(); } bool PlatformSensor::getSensors(DynamicVector *sensors) { CHRE_ASSERT(sensors); SeeHelper& seeHelper = *getSeeHelper(); DynamicVector tempSensors; if (!getSuidAndAttrs(seeHelper, "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]; SensorType sensorType = getSensorTypeFromDataType( dataType, false /* calibrated */); if (sensorType == SensorType::Unknown) { 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 == SensorType::InstantMotion && i == kNumSeeTypes - 1) { sensorType = SensorType::StationaryDetect; // Skip additional types or InstantMotion will be added to the sensor list // twice. skipAdditionalTypes = true; } #endif findAndAddSensorsForType(seeHelper, tempSensors, dataType, sensorType, skipAdditionalTypes, sensors); } #ifdef CHRE_SLPI_UIMG_ENABLED getBigImageSensors(sensors); #endif return true; } bool PlatformSensor::applyRequest(const SensorRequest& request) { SeeSensorRequest req = { .sensorType = getSensorType(), .enable = (request.getMode() != SensorMode::Off), .passive = sensorModeIsPassive(request.getMode()), .samplingRateHz = static_cast( kOneSecondInNanoseconds / request.getInterval().toRawNanoseconds()), // Override batch period to 0 for non-continuous sensors to ensure one // sample per batch. .batchPeriodUs = !sensorTypeIsContinuous(mSensorType) ? 0 : static_cast(request.getLatency().toRawNanoseconds() / kOneMicrosecondInNanoseconds), }; if (req.enable && req.passive && !mPassiveSupported) { LOGD("Promoting sensor %" PRIu8 " passive request to active", static_cast(getSensorType())); } SeeHelper *seeHelper = getSeeHelperForSensorType(getSensorType()); bool wasInUImage = slpiInUImage(); bool success = true; // TODO(b/150144912): Merge the two implementations to avoid having separate // code paths. #ifdef CHRE_SLPI_DEFAULT_BUILD // Calibration updates are not enabled automatically in the default build. SeeCalHelper *calHelper = seeHelper->getCalHelper(); const sns_std_suid *suid = calHelper->getCalSuidFromSensorType(getSensorType()); bool wereCalUpdatesEnabled = false; if (suid != nullptr) { wereCalUpdatesEnabled = calHelper->areCalUpdatesEnabled(*suid); success = calHelper->configureCalUpdates(*suid, req.enable, *seeHelper); } #endif if (success) { success = seeHelper->makeRequest(req); } #ifdef CHRE_SLPI_DEFAULT_BUILD // If any part of the configuration process failed, reset our subscription // for calibration updates to its previous value to attempt to restore state. if (suid != nullptr && !success) { bool areCalUpdatesEnabled = calHelper->areCalUpdatesEnabled(*suid); if (areCalUpdatesEnabled != wereCalUpdatesEnabled) { calHelper->configureCalUpdates(*suid, wereCalUpdatesEnabled, *seeHelper); } } #endif // 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) { if (request.getMode() == SensorMode::Off) { mLastEventValid = false; } // TODO: remove setSamplingStatus when .latency is available in status // update from SEE. struct chreSensorSamplingStatus status; if (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 (!mPassiveSupported) { status.enabled = req.enable; } status.latency = req.batchPeriodUs * kOneMicrosecondInNanoseconds; setSamplingStatus(status); } } return success; } bool PlatformSensor::flushAsync() { SensorType sensorType = getSensorType(); return getSeeHelperForSensorType(sensorType)->flush(sensorType); } SensorType PlatformSensor::getSensorType() const { return mSensorType; } uint64_t PlatformSensor::getMinInterval() const { return mMinInterval; } const char *PlatformSensor::getSensorName() const { return mSensorName; } PlatformSensor::PlatformSensor(PlatformSensor&& other) { // Our move assignment operator doesn't assume that "this" is initialized, so // we can just use that here. *this = std::move(other); } PlatformSensor& PlatformSensor::operator=(PlatformSensor&& other) { // Note: if this implementation is ever changed to depend on "this" containing // initialized values, the move constructor implemenation must be updated. mSensorType = other.mSensorType; mMinInterval = other.mMinInterval; memcpy(mSensorName, other.mSensorName, kSensorNameMaxLen); mLastEvent = other.mLastEvent; other.mLastEvent = nullptr; mLastEventSize = other.mLastEventSize; other.mLastEventSize = 0; mLastEventValid = other.mLastEventValid; mSamplingStatus = other.mSamplingStatus; mPassiveSupported = other.mPassiveSupported; return *this; } ChreSensorData *PlatformSensor::getLastEvent() const { return mLastEventValid ? mLastEvent : nullptr; } bool PlatformSensor::getSamplingStatus( struct chreSensorSamplingStatus *status) const { CHRE_ASSERT(status); memcpy(status, &mSamplingStatus, sizeof(*status)); return true; } bool PlatformSensor::getThreeAxisBias( struct chreSensorThreeAxisData *bias) const { SensorType sensorType = getSensorType(); SeeCalHelper *calHelper = getSeeHelperForSensorType(sensorType)->getCalHelper(); bool success = sensorTypeReportsBias(sensorType); if (success) { // We use the runtime-calibrated sensor type here, per documentation // of SeeCalHelper::getBias(), but overwrite the sensorHandle to that of // the curent sensor, because the calibration data itself is equivalent // for both calibrated/uncalibrated sensor types. #ifdef CHRE_SLPI_UIMG_ENABLED // Use the uimg runtime-calibrated sensor type to get the calibration // bias, since SeeCalHelper is unaware of the bimg/uimg differentiation. SensorType calSensorType = toCalibratedSensorType(getUimgSensorType(sensorType)); #else SensorType calSensorType = toCalibratedSensorType(sensorType); #endif if (calHelper->getBias(calSensorType, bias)) { bias->header.sensorHandle = getSensorHandleFromSensorType(sensorType); } else { // Set to zero value + unknown accuracy per CHRE API requirements. memset(bias, 0, sizeof(chreSensorThreeAxisData)); bias->header.accuracy = CHRE_SENSOR_ACCURACY_UNKNOWN; } } return success; } void PlatformSensorBase::initBase( SensorType sensorType,uint64_t minInterval, const char *sensorName, ChreSensorData *lastEvent, size_t lastEventSize, bool passiveSupported) { mSensorType = sensorType; mMinInterval = minInterval; memcpy(mSensorName, sensorName, kSensorNameMaxLen); mLastEvent = lastEvent; mLastEventSize = lastEventSize; mSamplingStatus.enabled = false; mSamplingStatus.interval = CHRE_SENSOR_INTERVAL_DEFAULT; mSamplingStatus.latency = CHRE_SENSOR_LATENCY_DEFAULT; mPassiveSupported = passiveSupported; } void PlatformSensorBase::setLastEvent(const ChreSensorData *event) { memcpy(mLastEvent, event, mLastEventSize); mLastEventValid = true; } void PlatformSensorBase::setSamplingStatus( const struct chreSensorSamplingStatus& status) { mSamplingStatus = status; } } // namespace chre