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 ops.sampleRate = checkSampleRate(*config, ops.sampleRate); 146 } 147 148 std::list<SubscribeOptions> updatedOptions; 149 auto res = mSubscriptionManager.addOrUpdateSubscription(getClientId(callback), 150 callback, verifiedOptions, 151 &updatedOptions); 152 if (StatusCode::OK != res) { 153 ALOGW("%s failed to subscribe, error code: %d", __func__, res); 154 return res; 155 } 156 157 for (auto opt : updatedOptions) { 158 mHal->subscribe(opt.propId, opt.sampleRate); 159 } 160 161 return StatusCode::OK; 162 } 163 164 Return<StatusCode> VehicleHalManager::unsubscribe(const sp<IVehicleCallback>& callback, 165 int32_t propId) { 166 mSubscriptionManager.unsubscribe(getClientId(callback), propId); 167 return StatusCode::OK; 168 } 169 170 Return<void> VehicleHalManager::debugDump(IVehicle::debugDump_cb _hidl_cb) { 171 _hidl_cb(""); 172 return Void(); 173 } 174 175 void VehicleHalManager::init() { 176 ALOGI("VehicleHalManager::init"); 177 178 mHidlVecOfVehiclePropValuePool.resize(kMaxHidlVecOfVehiclPropValuePoolSize); 179 180 181 mBatchingConsumer.run(&mEventQueue, 182 kHalEventBatchingTimeWindow, 183 std::bind(&VehicleHalManager::onBatchHalEvent, 184 this, _1)); 185 186 mHal->init(&mValueObjectPool, 187 std::bind(&VehicleHalManager::onHalEvent, this, _1), 188 std::bind(&VehicleHalManager::onHalPropertySetError, this, 189 _1, _2, _3)); 190 191 // Initialize index with vehicle configurations received from VehicleHal. 192 auto supportedPropConfigs = mHal->listProperties(); 193 mConfigIndex.reset(new VehiclePropConfigIndex(supportedPropConfigs)); 194 195 std::vector<int32_t> supportedProperties( 196 supportedPropConfigs.size()); 197 for (const auto& config : supportedPropConfigs) { 198 supportedProperties.push_back(config.prop); 199 } 200 } 201 202 VehicleHalManager::~VehicleHalManager() { 203 mBatchingConsumer.requestStop(); 204 mEventQueue.deactivate(); 205 // We have to wait until consumer thread is fully stopped because it may 206 // be in a state of running callback (onBatchHalEvent). 207 mBatchingConsumer.waitStopped(); 208 ALOGI("VehicleHalManager::dtor"); 209 } 210 211 void VehicleHalManager::onHalEvent(VehiclePropValuePtr v) { 212 mEventQueue.push(std::move(v)); 213 } 214 215 void VehicleHalManager::onHalPropertySetError(StatusCode errorCode, 216 int32_t property, 217 int32_t areaId) { 218 const auto& clients = 219 mSubscriptionManager.getSubscribedClients(property, SubscribeFlags::EVENTS_FROM_CAR); 220 221 for (auto client : clients) { 222 client->getCallback()->onPropertySetError(errorCode, property, areaId); 223 } 224 } 225 226 void VehicleHalManager::onBatchHalEvent(const std::vector<VehiclePropValuePtr>& values) { 227 const auto& clientValues = 228 mSubscriptionManager.distributeValuesToClients(values, SubscribeFlags::EVENTS_FROM_CAR); 229 230 for (const HalClientValues& cv : clientValues) { 231 auto vecSize = cv.values.size(); 232 hidl_vec<VehiclePropValue> vec; 233 if (vecSize < kMaxHidlVecOfVehiclPropValuePoolSize) { 234 vec.setToExternal(&mHidlVecOfVehiclePropValuePool[0], vecSize); 235 } else { 236 vec.resize(vecSize); 237 } 238 239 int i = 0; 240 for (VehiclePropValue* pValue : cv.values) { 241 shallowCopy(&(vec)[i++], *pValue); 242 } 243 auto status = cv.client->getCallback()->onPropertyEvent(vec); 244 if (!status.isOk()) { 245 ALOGE("Failed to notify client %s, err: %s", 246 toString(cv.client->getCallback()).c_str(), 247 status.description().c_str()); 248 } 249 } 250 } 251 252 bool VehicleHalManager::isSampleRateFixed(VehiclePropertyChangeMode mode) { 253 return (mode & VehiclePropertyChangeMode::ON_CHANGE); 254 } 255 256 float VehicleHalManager::checkSampleRate(const VehiclePropConfig &config, 257 float sampleRate) { 258 if (isSampleRateFixed(config.changeMode)) { 259 if (std::abs(sampleRate) > std::numeric_limits<float>::epsilon()) { 260 ALOGW("Sample rate is greater than zero for on change type. " 261 "Ignoring it."); 262 } 263 return 0.0; 264 } else { 265 if (sampleRate > config.maxSampleRate) { 266 ALOGW("Sample rate %f is higher than max %f. Setting sampling rate " 267 "to max.", sampleRate, config.maxSampleRate); 268 return config.maxSampleRate; 269 } 270 if (sampleRate < config.minSampleRate) { 271 ALOGW("Sample rate %f is lower than min %f. Setting sampling rate " 272 "to min.", sampleRate, config.minSampleRate); 273 return config.minSampleRate; 274 } 275 } 276 return sampleRate; // Provided sample rate was good, no changes. 277 } 278 279 bool VehicleHalManager::isSubscribable(const VehiclePropConfig& config, 280 SubscribeFlags flags) { 281 bool isReadable = config.access & VehiclePropertyAccess::READ; 282 283 if (!isReadable && (SubscribeFlags::EVENTS_FROM_CAR & flags)) { 284 ALOGW("Cannot subscribe, property 0x%x is not readable", config.prop); 285 return false; 286 } 287 if (config.changeMode == VehiclePropertyChangeMode::STATIC) { 288 ALOGW("Cannot subscribe, property 0x%x is static", config.prop); 289 return false; 290 } 291 return true; 292 } 293 294 bool VehicleHalManager::checkWritePermission(const VehiclePropConfig &config) const { 295 if (!(config.access & VehiclePropertyAccess::WRITE)) { 296 ALOGW("Property 0%x has no write access", config.prop); 297 return false; 298 } else { 299 return true; 300 } 301 } 302 303 bool VehicleHalManager::checkReadPermission(const VehiclePropConfig &config) const { 304 if (!(config.access & VehiclePropertyAccess::READ)) { 305 ALOGW("Property 0%x has no read access", config.prop); 306 return false; 307 } else { 308 return true; 309 } 310 } 311 312 void VehicleHalManager::handlePropertySetEvent(const VehiclePropValue& value) { 313 auto clients = 314 mSubscriptionManager.getSubscribedClients(value.prop, SubscribeFlags::EVENTS_FROM_ANDROID); 315 for (auto client : clients) { 316 client->getCallback()->onPropertySet(value); 317 } 318 } 319 320 const VehiclePropConfig* VehicleHalManager::getPropConfigOrNull( 321 int32_t prop) const { 322 return mConfigIndex->hasConfig(prop) 323 ? &mConfigIndex->getConfig(prop) : nullptr; 324 } 325 326 void VehicleHalManager::onAllClientsUnsubscribed(int32_t propertyId) { 327 mHal->unsubscribe(propertyId); 328 } 329 330 ClientId VehicleHalManager::getClientId(const sp<IVehicleCallback>& callback) { 331 //TODO(b/32172906): rework this to get some kind of unique id for callback interface when this 332 // feature is ready in HIDL. 333 334 if (callback->isRemote()) { 335 BpHwVehicleCallback* hwCallback = static_cast<BpHwVehicleCallback*>(callback.get()); 336 return static_cast<ClientId>(reinterpret_cast<intptr_t>(hwCallback->onAsBinder())); 337 } else { 338 return static_cast<ClientId>(reinterpret_cast<intptr_t>(callback.get())); 339 } 340 } 341 342 } // namespace V2_0 343 } // namespace vehicle 344 } // namespace automotive 345 } // namespace hardware 346 } // namespace android 347