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
28 namespace android {
29 namespace hardware {
30 namespace automotive {
31 namespace vehicle {
32 namespace V2_0 {
33
mergeSubscribeOptions(const SubscribeOptions & oldOpts,const SubscribeOptions & newOpts,SubscribeOptions * outResult)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
addOrUpdateSubscription(const SubscribeOptions & opts)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
isSubscribed(int32_t propId,SubscribeFlags flags)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
getSubscribedProperties() const77 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
addOrUpdateSubscription(ClientId clientId,const sp<IVehicleCallback> & callback,const hidl_vec<SubscribeOptions> & optionList,std::list<SubscribeOptions> * outUpdatedSubscriptions)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
distributeValuesToClients(const std::vector<recyclable_ptr<VehiclePropValue>> & propValues,SubscribeFlags flags) const120 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
getSubscribedClients(int32_t propId,SubscribeFlags flags) const147 std::list<sp<HalClient>> SubscriptionManager::getSubscribedClients(int32_t propId,
148 SubscribeFlags flags) const {
149 MuxGuard g(mLock);
150 return getSubscribedClientsLocked(propId, flags);
151 }
152
getSubscribedClientsLocked(int32_t propId,SubscribeFlags flags) const153 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
updateHalEventSubscriptionLocked(const SubscribeOptions & opts,SubscribeOptions * outUpdated)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
addClientToPropMapLocked(int32_t propId,const sp<HalClient> & client)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
getClientsForPropertyLocked(int32_t propId) const204 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
getOrCreateHalClientLocked(ClientId clientId,const sp<IVehicleCallback> & callback)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
unsubscribe(ClientId clientId,int32_t propId)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
onCallbackDead(uint64_t cookie)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