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         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