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@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 28namespace android { 29namespace hardware { 30namespace automotive { 31namespace vehicle { 32namespace V2_0 { 33 34bool 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 50void 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 66bool 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 77std::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 86StatusCode 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 120std::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 147std::list<sp<HalClient>> SubscriptionManager::getSubscribedClients(int32_t propId, 148 SubscribeFlags flags) const { 149 MuxGuard g(mLock); 150 return getSubscribedClientsLocked(propId, flags); 151} 152 153std::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 170bool 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 191void 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 204sp<HalClientVector> SubscriptionManager::getClientsForPropertyLocked( 205 int32_t propId) const { 206 auto it = mPropToClients.find(propId); 207 return it == mPropToClients.end() ? nullptr : it->second; 208} 209 210sp<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 232void 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 274void 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