1 /* 2 * Copyright (C) 2016 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 #define LOG_TAG "automotive.vehicle (at) 2.0-impl" 18 19 #include "VehicleHalManager.h" 20 21 #include <cmath> 22 #include <fstream> 23 24 #include <android/log.h> 25 #include <android/hardware/automotive/vehicle/2.0/BpHwVehicleCallback.h> 26 27 #include "VehicleUtils.h" 28 29 namespace android { 30 namespace hardware { 31 namespace automotive { 32 namespace vehicle { 33 namespace V2_0 { 34 35 using namespace std::placeholders; 36 37 constexpr std::chrono::milliseconds kHalEventBatchingTimeWindow(10); 38 39 const VehiclePropValue kEmptyValue{}; 40 41 /** 42 * Indicates what's the maximum size of hidl_vec<VehiclePropValue> we want 43 * to store in reusable object pool. 44 */ 45 constexpr auto kMaxHidlVecOfVehiclPropValuePoolSize = 20; 46 47 Return<void> VehicleHalManager::getAllPropConfigs(getAllPropConfigs_cb _hidl_cb) { 48 ALOGI("getAllPropConfigs called"); 49 hidl_vec<VehiclePropConfig> hidlConfigs; 50 auto& halConfig = mConfigIndex->getAllConfigs(); 51 52 hidlConfigs.setToExternal( 53 const_cast<VehiclePropConfig *>(halConfig.data()), 54 halConfig.size()); 55 56 _hidl_cb(hidlConfigs); 57 58 return Void(); 59 } 60 61 Return<void> VehicleHalManager::getPropConfigs(const hidl_vec<int32_t> &properties, 62 getPropConfigs_cb _hidl_cb) { 63 std::vector<VehiclePropConfig> configs; 64 for (size_t i = 0; i < properties.size(); i++) { 65 auto prop = properties[i]; 66 if (mConfigIndex->hasConfig(prop)) { 67 configs.push_back(mConfigIndex->getConfig(prop)); 68 } else { 69 ALOGW("Requested config for undefined property: 0x%x", prop); 70 _hidl_cb(StatusCode::INVALID_ARG, hidl_vec<VehiclePropConfig>()); 71 } 72 } 73 74 _hidl_cb(StatusCode::OK, configs); 75 76 return Void(); 77 } 78 79 Return<void> VehicleHalManager::get(const VehiclePropValue& requestedPropValue, get_cb _hidl_cb) { 80 const auto* config = getPropConfigOrNull(requestedPropValue.prop); 81 if (config == nullptr) { 82 ALOGE("Failed to get value: config not found, property: 0x%x", 83 requestedPropValue.prop); 84 _hidl_cb(StatusCode::INVALID_ARG, kEmptyValue); 85 return Void(); 86 } 87 88 if (!checkReadPermission(*config)) { 89 _hidl_cb(StatusCode::ACCESS_DENIED, kEmptyValue); 90 return Void(); 91 } 92 93 StatusCode status; 94 auto value = mHal->get(requestedPropValue, &status); 95 _hidl_cb(status, value.get() ? *value : kEmptyValue); 96 97 98 return Void(); 99 } 100 101 Return<StatusCode> VehicleHalManager::set(const VehiclePropValue &value) { 102 auto prop = value.prop; 103 const auto* config = getPropConfigOrNull(prop); 104 if (config == nullptr) { 105 ALOGE("Failed to set value: config not found, property: 0x%x", prop); 106 return StatusCode::INVALID_ARG; 107 } 108 109 if (!checkWritePermission(*config)) { 110 return StatusCode::ACCESS_DENIED; 111 } 112 113 handlePropertySetEvent(value); 114 115 auto status = mHal->set(value); 116 117 return Return<StatusCode>(status); 118 } 119 120 Return<StatusCode> VehicleHalManager::subscribe(const sp<IVehicleCallback> &callback, 121 const hidl_vec<SubscribeOptions> &options) { 122 hidl_vec<SubscribeOptions> verifiedOptions(options); 123 for (size_t i = 0; i < verifiedOptions.size(); i++) { 124 SubscribeOptions& ops = verifiedOptions[i]; 125 auto prop = ops.propId; 126 127 const auto* config = getPropConfigOrNull(prop); 128 if (config == nullptr) { 129 ALOGE("Failed to subscribe: config not found, property: 0x%x", 130 prop); 131 return StatusCode::INVALID_ARG; 132 } 133 134 if (ops.flags == SubscribeFlags::UNDEFINED) { 135 ALOGE("Failed to subscribe: undefined flag in options provided"); 136 return StatusCode::INVALID_ARG; 137 } 138 139 if (!isSubscribable(*config, ops.flags)) { 140 ALOGE("Failed to subscribe: property 0x%x is not subscribable", 141 prop); 142 return StatusCode::INVALID_ARG; 143 } 144 145 int32_t areas = isGlobalProp(prop) ? 0 : ops.vehicleAreas; 146 if (areas != 0 && ((areas & config->supportedAreas) != areas)) { 147 ALOGE("Failed to subscribe property 0x%x. Requested areas 0x%x are " 148 "out of supported range of 0x%x", prop, ops.vehicleAreas, 149 config->supportedAreas); 150 return StatusCode::INVALID_ARG; 151 } 152 153 ops.vehicleAreas = areas; 154 ops.sampleRate = checkSampleRate(*config, ops.sampleRate); 155 } 156 157 std::list<SubscribeOptions> updatedOptions; 158 auto res = mSubscriptionManager.addOrUpdateSubscription(getClientId(callback), 159 callback, verifiedOptions, 160 &updatedOptions); 161 if (StatusCode::OK != res) { 162 ALOGW("%s failed to subscribe, error code: %d", __func__, res); 163 return res; 164 } 165 166 for (auto opt : updatedOptions) { 167 mHal->subscribe(opt.propId, opt.vehicleAreas, opt.sampleRate); 168 } 169 170 return StatusCode::OK; 171 } 172 173 Return<StatusCode> VehicleHalManager::unsubscribe(const sp<IVehicleCallback>& callback, 174 int32_t propId) { 175 mSubscriptionManager.unsubscribe(getClientId(callback), propId); 176 return StatusCode::OK; 177 } 178 179 Return<void> VehicleHalManager::debugDump(IVehicle::debugDump_cb _hidl_cb) { 180 _hidl_cb(""); 181 return Void(); 182 } 183 184 void VehicleHalManager::init() { 185 ALOGI("VehicleHalManager::init"); 186 187 mHidlVecOfVehiclePropValuePool.resize(kMaxHidlVecOfVehiclPropValuePoolSize); 188 189 190 mBatchingConsumer.run(&mEventQueue, 191 kHalEventBatchingTimeWindow, 192 std::bind(&VehicleHalManager::onBatchHalEvent, 193 this, _1)); 194 195 mHal->init(&mValueObjectPool, 196 std::bind(&VehicleHalManager::onHalEvent, this, _1), 197 std::bind(&VehicleHalManager::onHalPropertySetError, this, 198 _1, _2, _3)); 199 200 // Initialize index with vehicle configurations received from VehicleHal. 201 auto supportedPropConfigs = mHal->listProperties(); 202 mConfigIndex.reset(new VehiclePropConfigIndex(supportedPropConfigs)); 203 204 std::vector<int32_t> supportedProperties( 205 supportedPropConfigs.size()); 206 for (const auto& config : supportedPropConfigs) { 207 supportedProperties.push_back(config.prop); 208 } 209 } 210 211 VehicleHalManager::~VehicleHalManager() { 212 mBatchingConsumer.requestStop(); 213 mEventQueue.deactivate(); 214 // We have to wait until consumer thread is fully stopped because it may 215 // be in a state of running callback (onBatchHalEvent). 216 mBatchingConsumer.waitStopped(); 217 ALOGI("VehicleHalManager::dtor"); 218 } 219 220 void VehicleHalManager::onHalEvent(VehiclePropValuePtr v) { 221 mEventQueue.push(std::move(v)); 222 } 223 224 void VehicleHalManager::onHalPropertySetError(StatusCode errorCode, 225 int32_t property, 226 int32_t areaId) { 227 const auto& clients = mSubscriptionManager.getSubscribedClients( 228 property, 0, SubscribeFlags::HAL_EVENT); 229 230 for (auto client : clients) { 231 client->getCallback()->onPropertySetError(errorCode, property, areaId); 232 } 233 } 234 235 void VehicleHalManager::onBatchHalEvent(const std::vector<VehiclePropValuePtr>& values) { 236 const auto& clientValues = mSubscriptionManager.distributeValuesToClients( 237 values, SubscribeFlags::HAL_EVENT); 238 239 for (const HalClientValues& cv : clientValues) { 240 auto vecSize = cv.values.size(); 241 hidl_vec<VehiclePropValue> vec; 242 if (vecSize < kMaxHidlVecOfVehiclPropValuePoolSize) { 243 vec.setToExternal(&mHidlVecOfVehiclePropValuePool[0], vecSize); 244 } else { 245 vec.resize(vecSize); 246 } 247 248 int i = 0; 249 for (VehiclePropValue* pValue : cv.values) { 250 shallowCopy(&(vec)[i++], *pValue); 251 } 252 auto status = cv.client->getCallback()->onPropertyEvent(vec); 253 if (!status.isOk()) { 254 ALOGE("Failed to notify client %s, err: %s", 255 toString(cv.client->getCallback()).c_str(), 256 status.description().c_str()); 257 } 258 } 259 } 260 261 bool VehicleHalManager::isSampleRateFixed(VehiclePropertyChangeMode mode) { 262 return (mode & VehiclePropertyChangeMode::ON_SET) 263 || (mode & VehiclePropertyChangeMode::ON_CHANGE); 264 } 265 266 float VehicleHalManager::checkSampleRate(const VehiclePropConfig &config, 267 float sampleRate) { 268 if (isSampleRateFixed(config.changeMode)) { 269 if (std::abs(sampleRate) > std::numeric_limits<float>::epsilon()) { 270 ALOGW("Sample rate is greater than zero for on change type. " 271 "Ignoring it."); 272 } 273 return 0.0; 274 } else { 275 if (sampleRate > config.maxSampleRate) { 276 ALOGW("Sample rate %f is higher than max %f. Setting sampling rate " 277 "to max.", sampleRate, config.maxSampleRate); 278 return config.maxSampleRate; 279 } 280 if (sampleRate < config.minSampleRate) { 281 ALOGW("Sample rate %f is lower than min %f. Setting sampling rate " 282 "to min.", sampleRate, config.minSampleRate); 283 return config.minSampleRate; 284 } 285 } 286 return sampleRate; // Provided sample rate was good, no changes. 287 } 288 289 bool VehicleHalManager::isSubscribable(const VehiclePropConfig& config, 290 SubscribeFlags flags) { 291 bool isReadable = config.access & VehiclePropertyAccess::READ; 292 293 if (!isReadable && (SubscribeFlags::HAL_EVENT & flags)) { 294 ALOGW("Cannot subscribe, property 0x%x is not readable", config.prop); 295 return false; 296 } 297 if (config.changeMode == VehiclePropertyChangeMode::STATIC) { 298 ALOGW("Cannot subscribe, property 0x%x is static", config.prop); 299 return false; 300 } 301 302 //TODO: extend to support event notification for set from android 303 if (config.changeMode == VehiclePropertyChangeMode::POLL) { 304 ALOGW("Cannot subscribe, property 0x%x is poll only", config.prop); 305 return false; 306 } 307 return true; 308 } 309 310 bool VehicleHalManager::checkWritePermission(const VehiclePropConfig &config) const { 311 if (!(config.access & VehiclePropertyAccess::WRITE)) { 312 ALOGW("Property 0%x has no write access", config.prop); 313 return false; 314 } else { 315 return true; 316 } 317 } 318 319 bool VehicleHalManager::checkReadPermission(const VehiclePropConfig &config) const { 320 if (!(config.access & VehiclePropertyAccess::READ)) { 321 ALOGW("Property 0%x has no read access", config.prop); 322 return false; 323 } else { 324 return true; 325 } 326 } 327 328 void VehicleHalManager::handlePropertySetEvent(const VehiclePropValue& value) { 329 auto clients = mSubscriptionManager.getSubscribedClients( 330 value.prop, value.areaId, SubscribeFlags::SET_CALL); 331 for (auto client : clients) { 332 client->getCallback()->onPropertySet(value); 333 } 334 } 335 336 const VehiclePropConfig* VehicleHalManager::getPropConfigOrNull( 337 int32_t prop) const { 338 return mConfigIndex->hasConfig(prop) 339 ? &mConfigIndex->getConfig(prop) : nullptr; 340 } 341 342 void VehicleHalManager::onAllClientsUnsubscribed(int32_t propertyId) { 343 mHal->unsubscribe(propertyId); 344 } 345 346 ClientId VehicleHalManager::getClientId(const sp<IVehicleCallback>& callback) { 347 //TODO(b/32172906): rework this to get some kind of unique id for callback interface when this 348 // feature is ready in HIDL. 349 350 if (callback->isRemote()) { 351 BpHwVehicleCallback* hwCallback = static_cast<BpHwVehicleCallback*>(callback.get()); 352 return static_cast<ClientId>(reinterpret_cast<intptr_t>(hwCallback->onAsBinder())); 353 } else { 354 return static_cast<ClientId>(reinterpret_cast<intptr_t>(callback.get())); 355 } 356 } 357 358 } // namespace V2_0 359 } // namespace vehicle 360 } // namespace automotive 361 } // namespace hardware 362 } // namespace android 363