Home | History | Annotate | Download | only in src
      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