/* * Copyright 2020 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 "VhalHandler.h" #include #include #include #include #include #include #include #include #include namespace android { namespace hardware { namespace automotive { namespace sv { namespace V1_0 { namespace implementation { using vehicle::V2_0::IVehicle; using vehicle::V2_0::StatusCode; using vehicle::V2_0::VehiclePropertyType; using vehicle::V2_0::VehiclePropValue; bool VhalHandler::initialize(UpdateMethod updateMethod, int rate) { LOG(DEBUG) << __FUNCTION__; std::scoped_lock lock(mAccessLock); if (mIsInitialized) { LOG(ERROR) << "Vehicle Handler is already initialized."; return false; } LOG(INFO) << "Connecting to Vehicle HAL"; mVhalServicePtr = IVehicle::getService(); if (mVhalServicePtr.get() == nullptr) { LOG(ERROR) << "Vehicle HAL getService failed."; return false; } if (rate < 1 || rate > 100) { LOG(ERROR) << "Rate must be in the range [1, 100]."; return false; } if (mUpdateMethod == UpdateMethod::SUBSCRIBE) { LOG(ERROR) << "Update method Subscribe is not currently implemented."; return false; } mUpdateMethod = updateMethod; mRate = rate; mIsInitialized = true; mIsUpdateActive = false; return true; } void VhalHandler::pollProperties() { LOG(DEBUG) << "Polling thread started."; while (true) { nsecs_t startTime = elapsedRealtimeNano(); // Copy properties to read. std::vector propertiesToRead; int rate; { std::scoped_lock lock(mAccessLock); if (!mIsUpdateActive) { LOG(DEBUG) << "Exiting polling thread."; break; } propertiesToRead = mPropertiesToRead; rate = mRate; } // Make get call for each VHAL property. // Write to back property values, note lock is not needed as only this thread uses it. std::vector vehiclePropValuesUpdated; for (auto& propertyToRead : propertiesToRead) { StatusCode statusResult; VehiclePropValue propValueResult; mVhalServicePtr->get(propertyToRead, [&statusResult, &propValueResult](StatusCode status, const VehiclePropValue& propValue) { statusResult = status; propValueResult = propValue; }); if (statusResult != StatusCode::OK) { LOG(WARNING) << "Failed to read vhal property: " << propertyToRead.prop << ", with status code: " << static_cast(statusResult); } else { vehiclePropValuesUpdated.push_back(propValueResult); } } // Update property values by swapping with updated property values. { std::scoped_lock lock(mAccessLock); std::swap(mPropertyValues, vehiclePropValuesUpdated); } std::unique_lock sleepLock(mPollThreadSleepMutex); // Sleep to generate frames at kTargetFrameRate. // rate is number of updates per seconds, // Target time period between two updates in nano-seconds = (10 ^ 9) / rate. const nsecs_t kTargetRateNs = std::pow(10, 9) / mRate; const nsecs_t now = elapsedRealtimeNano(); const nsecs_t workTimeNs = now - startTime; const nsecs_t sleepDurationNs = kTargetRateNs - workTimeNs; if (sleepDurationNs > 0) { // Sleep for sleepDurationNs or until a stop signal is received. mPollThreadCondition.wait_for(sleepLock, std::chrono::nanoseconds(sleepDurationNs), [this]() { return mPollStopSleeping; }); } } } bool VhalHandler::startPropertiesUpdate() { LOG(DEBUG) << __FUNCTION__; std::scoped_lock lock(mAccessLock); // Check Vhal service is initialized. if (!mIsInitialized) { LOG(ERROR) << "VHAL handler not initialized."; return false; } if (mIsUpdateActive) { LOG(ERROR) << "Polling is already started."; return false; } mIsUpdateActive = true; { std::scoped_lock sleepLock(mPollThreadSleepMutex); mPollStopSleeping = false; } // Start polling thread if updated method is GET. if (mUpdateMethod == UpdateMethod::GET) { mPollingThread = std::thread([this]() { pollProperties(); }); } return true; } bool VhalHandler::setPropertiesToRead(const std::vector& propertiesToRead) { LOG(DEBUG) << __FUNCTION__; std::scoped_lock lock(mAccessLock); // Replace property ids to read. mPropertiesToRead = propertiesToRead; return true; } bool VhalHandler::setPropertiesToRead(const std::vector& propertiesToRead) { LOG(DEBUG) << __FUNCTION__; std::vector vhalPropValues; for (const auto& property : propertiesToRead) { VehiclePropValue propValue; // Higher 32 bits = property id, lower 32 bits = area id. propValue.areaId = property & 0xFFFFFFFF; propValue.prop = (property >> 32) & 0xFFFFFFFF; vhalPropValues.push_back(propValue); } return setPropertiesToRead(vhalPropValues); } bool VhalHandler::getPropertyValues(std::vector* property_values) { LOG(DEBUG) << __FUNCTION__; std::scoped_lock lock(mAccessLock); // Check Vhal service is initialized. if (!mIsInitialized) { LOG(ERROR) << "VHAL handler not initialized."; return false; } // Copy current property values to argument. *property_values = mPropertyValues; return true; } bool VhalHandler::stopPropertiesUpdate() { LOG(DEBUG) << __FUNCTION__; { std::scoped_lock lock(mAccessLock); // Check Vhal service is initialized. if (!mIsInitialized) { LOG(ERROR) << "VHAL handler not initialized."; return false; } if (!mIsUpdateActive) { LOG(ERROR) << "Polling is already stopped."; return false; } mIsUpdateActive = false; } // Wake up the polling thread. { std::scoped_lock sleepLock(mPollThreadSleepMutex); mPollStopSleeping = true; } mPollThreadCondition.notify_one(); // Wait for polling thread to exit. mPollingThread.join(); return true; } } // namespace implementation } // namespace V1_0 } // namespace sv } // namespace automotive } // namespace hardware } // namespace android