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 "SubscriptionManager.h"
     20 
     21 #include <cmath>
     22 #include <inttypes.h>
     23 
     24 #include <android/log.h>
     25 
     26 #include "VehicleUtils.h"
     27 
     28 namespace android {
     29 namespace hardware {
     30 namespace automotive {
     31 namespace vehicle {
     32 namespace V2_0 {
     33 
     34 bool mergeSubscribeOptions(const SubscribeOptions &oldOpts,
     35                            const SubscribeOptions &newOpts,
     36                            SubscribeOptions *outResult) {
     37     float updatedRate = std::max(oldOpts.sampleRate, newOpts.sampleRate);
     38     SubscribeFlags updatedFlags = SubscribeFlags(oldOpts.flags | newOpts.flags);
     39 
     40     bool updated = (updatedRate > oldOpts.sampleRate) || (updatedFlags != oldOpts.flags);
     41     if (updated) {
     42         *outResult = oldOpts;
     43         outResult->sampleRate = updatedRate;
     44         outResult->flags = updatedFlags;
     45     }
     46 
     47     return updated;
     48 }
     49 
     50 void HalClient::addOrUpdateSubscription(const SubscribeOptions &opts)  {
     51     ALOGI("%s opts.propId: 0x%x", __func__, opts.propId);
     52 
     53     auto it = mSubscriptions.find(opts.propId);
     54     if (it == mSubscriptions.end()) {
     55         mSubscriptions.emplace(opts.propId, opts);
     56     } else {
     57         const SubscribeOptions& oldOpts = it->second;
     58         SubscribeOptions updatedOptions;
     59         if (mergeSubscribeOptions(oldOpts, opts, &updatedOptions)) {
     60             mSubscriptions.erase(it);
     61             mSubscriptions.emplace(opts.propId, updatedOptions);
     62         }
     63     }
     64 }
     65 
     66 bool HalClient::isSubscribed(int32_t propId,
     67                              SubscribeFlags flags) {
     68     auto it = mSubscriptions.find(propId);
     69     if (it == mSubscriptions.end()) {
     70         return false;
     71     }
     72     const SubscribeOptions& opts = it->second;
     73     bool res = (opts.flags & flags);
     74     return res;
     75 }
     76 
     77 std::vector<int32_t> HalClient::getSubscribedProperties() const {
     78     std::vector<int32_t> props;
     79     for (const auto& subscription : mSubscriptions) {
     80         ALOGI("%s propId: 0x%x, propId: 0x%x", __func__, subscription.first, subscription.second.propId);
     81         props.push_back(subscription.first);
     82     }
     83     return props;
     84 }
     85 
     86 StatusCode SubscriptionManager::addOrUpdateSubscription(
     87         ClientId clientId,
     88         const sp<IVehicleCallback> &callback,
     89         const hidl_vec<SubscribeOptions> &optionList,
     90         std::list<SubscribeOptions>* outUpdatedSubscriptions) {
     91     outUpdatedSubscriptions->clear();
     92 
     93     MuxGuard g(mLock);
     94 
     95     ALOGI("SubscriptionManager::addOrUpdateSubscription, callback: %p", callback.get());
     96 
     97     const sp<HalClient>& client = getOrCreateHalClientLocked(clientId, callback);
     98     if (client.get() == nullptr) {
     99         return StatusCode::INTERNAL_ERROR;
    100     }
    101 
    102     for (size_t i = 0; i < optionList.size(); i++) {
    103         const SubscribeOptions& opts = optionList[i];
    104         ALOGI("SubscriptionManager::addOrUpdateSubscription, prop: 0x%x", opts.propId);
    105         client->addOrUpdateSubscription(opts);
    106 
    107         addClientToPropMapLocked(opts.propId, client);
    108 
    109         if (SubscribeFlags::EVENTS_FROM_CAR & opts.flags) {
    110             SubscribeOptions updated;
    111             if (updateHalEventSubscriptionLocked(opts, &updated)) {
    112                 outUpdatedSubscriptions->push_back(updated);
    113             }
    114         }
    115     }
    116 
    117     return StatusCode::OK;
    118 }
    119 
    120 std::list<HalClientValues> SubscriptionManager::distributeValuesToClients(
    121         const std::vector<recyclable_ptr<VehiclePropValue>>& propValues,
    122         SubscribeFlags flags) const {
    123     std::map<sp<HalClient>, std::list<VehiclePropValue*>> clientValuesMap;
    124 
    125     {
    126         MuxGuard g(mLock);
    127         for (const auto& propValue: propValues) {
    128             VehiclePropValue* v = propValue.get();
    129             auto clients = getSubscribedClientsLocked(v->prop, flags);
    130             for (const auto& client : clients) {
    131                 clientValuesMap[client].push_back(v);
    132             }
    133         }
    134     }
    135 
    136     std::list<HalClientValues> clientValues;
    137     for (const auto& entry : clientValuesMap) {
    138         clientValues.push_back(HalClientValues {
    139             .client = entry.first,
    140             .values = entry.second
    141         });
    142     }
    143 
    144     return clientValues;
    145 }
    146 
    147 std::list<sp<HalClient>> SubscriptionManager::getSubscribedClients(int32_t propId,
    148                                                                    SubscribeFlags flags) const {
    149     MuxGuard g(mLock);
    150     return getSubscribedClientsLocked(propId, flags);
    151 }
    152 
    153 std::list<sp<HalClient>> SubscriptionManager::getSubscribedClientsLocked(
    154     int32_t propId, SubscribeFlags flags) const {
    155     std::list<sp<HalClient>> subscribedClients;
    156 
    157     sp<HalClientVector> propClients = getClientsForPropertyLocked(propId);
    158     if (propClients.get() != nullptr) {
    159         for (size_t i = 0; i < propClients->size(); i++) {
    160             const auto& client = propClients->itemAt(i);
    161             if (client->isSubscribed(propId, flags)) {
    162                 subscribedClients.push_back(client);
    163             }
    164         }
    165     }
    166 
    167     return subscribedClients;
    168 }
    169 
    170 bool SubscriptionManager::updateHalEventSubscriptionLocked(
    171         const SubscribeOptions &opts, SubscribeOptions *outUpdated) {
    172     bool updated = false;
    173     auto it = mHalEventSubscribeOptions.find(opts.propId);
    174     if (it == mHalEventSubscribeOptions.end()) {
    175         *outUpdated = opts;
    176         mHalEventSubscribeOptions.emplace(opts.propId, opts);
    177         updated = true;
    178     } else {
    179         const SubscribeOptions& oldOpts = it->second;
    180 
    181         if (mergeSubscribeOptions(oldOpts, opts, outUpdated)) {
    182             mHalEventSubscribeOptions.erase(opts.propId);
    183             mHalEventSubscribeOptions.emplace(opts.propId, *outUpdated);
    184             updated = true;
    185         }
    186     }
    187 
    188     return updated;
    189 }
    190 
    191 void SubscriptionManager::addClientToPropMapLocked(
    192         int32_t propId, const sp<HalClient> &client) {
    193     auto it = mPropToClients.find(propId);
    194     sp<HalClientVector> propClients;
    195     if (it == mPropToClients.end()) {
    196         propClients = new HalClientVector();
    197         mPropToClients.insert(std::make_pair(propId, propClients));
    198     } else {
    199         propClients = it->second;
    200     }
    201     propClients->addOrUpdate(client);
    202 }
    203 
    204 sp<HalClientVector> SubscriptionManager::getClientsForPropertyLocked(
    205         int32_t propId) const {
    206     auto it = mPropToClients.find(propId);
    207     return it == mPropToClients.end() ? nullptr : it->second;
    208 }
    209 
    210 sp<HalClient> SubscriptionManager::getOrCreateHalClientLocked(
    211         ClientId clientId, const sp<IVehicleCallback>& callback) {
    212     auto it = mClients.find(clientId);
    213 
    214     if (it == mClients.end()) {
    215         uint64_t cookie = reinterpret_cast<uint64_t>(clientId);
    216         ALOGI("Creating new client and linking to death recipient, cookie: 0x%" PRIx64, cookie);
    217         auto res = callback->linkToDeath(mCallbackDeathRecipient, cookie);
    218         if (!res.isOk()) {  // Client is already dead?
    219             ALOGW("%s failed to link to death, client %p, err: %s",
    220                   __func__, callback.get(), res.description().c_str());
    221             return nullptr;
    222         }
    223 
    224         sp<HalClient> client = new HalClient(callback);
    225         mClients.insert({clientId, client});
    226         return client;
    227     } else {
    228         return it->second;
    229     }
    230 }
    231 
    232 void SubscriptionManager::unsubscribe(ClientId clientId,
    233                                       int32_t propId) {
    234     MuxGuard g(mLock);
    235     auto propertyClients = getClientsForPropertyLocked(propId);
    236     auto clientIter = mClients.find(clientId);
    237     if (clientIter == mClients.end()) {
    238         ALOGW("Unable to unsubscribe: no callback found, propId: 0x%x", propId);
    239     } else {
    240         auto client = clientIter->second;
    241 
    242         if (propertyClients != nullptr) {
    243             propertyClients->remove(client);
    244 
    245             if (propertyClients->isEmpty()) {
    246                 mPropToClients.erase(propId);
    247             }
    248         }
    249 
    250         bool isClientSubscribedToOtherProps = false;
    251         for (const auto& propClient : mPropToClients) {
    252             if (propClient.second->indexOf(client) >= 0) {
    253                 isClientSubscribedToOtherProps = true;
    254                 break;
    255             }
    256         }
    257 
    258         if (!isClientSubscribedToOtherProps) {
    259             auto res = client->getCallback()->unlinkToDeath(mCallbackDeathRecipient);
    260             if (!res.isOk()) {
    261                 ALOGW("%s failed to unlink to death, client: %p, err: %s",
    262                       __func__, client->getCallback().get(), res.description().c_str());
    263             }
    264             mClients.erase(clientIter);
    265         }
    266     }
    267 
    268     if (propertyClients == nullptr || propertyClients->isEmpty()) {
    269         mHalEventSubscribeOptions.erase(propId);
    270         mOnPropertyUnsubscribed(propId);
    271     }
    272 }
    273 
    274 void SubscriptionManager::onCallbackDead(uint64_t cookie) {
    275     ALOGI("%s, cookie: 0x%" PRIx64, __func__, cookie);
    276     ClientId clientId = cookie;
    277 
    278     std::vector<int32_t> props;
    279     {
    280         MuxGuard g(mLock);
    281         const auto& it = mClients.find(clientId);
    282         if (it == mClients.end()) {
    283             return;  // Nothing to do here, client wasn't subscribed to any properties.
    284         }
    285         const auto& halClient = it->second;
    286         props = halClient->getSubscribedProperties();
    287     }
    288 
    289     for (int32_t propId : props) {
    290         unsubscribe(clientId, propId);
    291     }
    292 }
    293 
    294 
    295 }  // namespace V2_0
    296 }  // namespace vehicle
    297 }  // namespace automotive
    298 }  // namespace hardware
    299 }  // namespace android
    300