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