• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 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 #include "SubscriptionManager.h"
18 
19 #include <android-base/stringprintf.h>
20 #include <utils/Log.h>
21 #include <utils/SystemClock.h>
22 
23 #include <inttypes.h>
24 
25 namespace android {
26 namespace hardware {
27 namespace automotive {
28 namespace vehicle {
29 
30 namespace {
31 
32 constexpr float ONE_SECOND_IN_NANO = 1'000'000'000.;
33 
34 }  // namespace
35 
36 using ::aidl::android::hardware::automotive::vehicle::IVehicleCallback;
37 using ::aidl::android::hardware::automotive::vehicle::StatusCode;
38 using ::aidl::android::hardware::automotive::vehicle::SubscribeOptions;
39 using ::aidl::android::hardware::automotive::vehicle::VehiclePropError;
40 using ::aidl::android::hardware::automotive::vehicle::VehiclePropValue;
41 using ::android::base::Error;
42 using ::android::base::Result;
43 using ::android::base::StringPrintf;
44 using ::ndk::ScopedAStatus;
45 
SubscriptionManager(IVehicleHardware * vehicleHardware)46 SubscriptionManager::SubscriptionManager(IVehicleHardware* vehicleHardware)
47     : mVehicleHardware(vehicleHardware) {}
48 
~SubscriptionManager()49 SubscriptionManager::~SubscriptionManager() {
50     std::scoped_lock<std::mutex> lockGuard(mLock);
51 
52     mClientsByPropIdArea.clear();
53     mSubscribedPropsByClient.clear();
54 }
55 
checkSampleRateHz(float sampleRateHz)56 bool SubscriptionManager::checkSampleRateHz(float sampleRateHz) {
57     return getIntervalNanos(sampleRateHz).ok();
58 }
59 
getIntervalNanos(float sampleRateHz)60 Result<int64_t> SubscriptionManager::getIntervalNanos(float sampleRateHz) {
61     int64_t intervalNanos = 0;
62     if (sampleRateHz <= 0) {
63         return Error() << "invalid sample rate, must be a positive number";
64     }
65     if (sampleRateHz <= (ONE_SECOND_IN_NANO / static_cast<float>(INT64_MAX))) {
66         return Error() << "invalid sample rate: " << sampleRateHz << ", too small";
67     }
68     intervalNanos = static_cast<int64_t>(ONE_SECOND_IN_NANO / sampleRateHz);
69     return intervalNanos;
70 }
71 
refreshMaxSampleRateHz()72 void ContSubConfigs::refreshMaxSampleRateHz() {
73     float maxSampleRateHz = 0.;
74     // This is not called frequently so a brute-focre is okay. More efficient way exists but this
75     // is simpler.
76     for (const auto& [_, sampleRateHz] : mSampleRateHzByClient) {
77         if (sampleRateHz > maxSampleRateHz) {
78             maxSampleRateHz = sampleRateHz;
79         }
80     }
81     mMaxSampleRateHz = maxSampleRateHz;
82 }
83 
addClient(const ClientIdType & clientId,float sampleRateHz)84 void ContSubConfigs::addClient(const ClientIdType& clientId, float sampleRateHz) {
85     mSampleRateHzByClient[clientId] = sampleRateHz;
86     refreshMaxSampleRateHz();
87 }
88 
removeClient(const ClientIdType & clientId)89 void ContSubConfigs::removeClient(const ClientIdType& clientId) {
90     mSampleRateHzByClient.erase(clientId);
91     refreshMaxSampleRateHz();
92 }
93 
getMaxSampleRateHz() const94 float ContSubConfigs::getMaxSampleRateHz() const {
95     return mMaxSampleRateHz;
96 }
97 
addContinuousSubscriberLocked(const ClientIdType & clientId,const PropIdAreaId & propIdAreaId,float sampleRateHz)98 VhalResult<void> SubscriptionManager::addContinuousSubscriberLocked(
99         const ClientIdType& clientId, const PropIdAreaId& propIdAreaId, float sampleRateHz) {
100     // Make a copy so that we don't modify 'mContSubConfigsByPropIdArea' on failure cases.
101     ContSubConfigs newConfig = mContSubConfigsByPropIdArea[propIdAreaId];
102     newConfig.addClient(clientId, sampleRateHz);
103     return updateContSubConfigs(propIdAreaId, newConfig);
104 }
105 
removeContinuousSubscriberLocked(const ClientIdType & clientId,const PropIdAreaId & propIdAreaId)106 VhalResult<void> SubscriptionManager::removeContinuousSubscriberLocked(
107         const ClientIdType& clientId, const PropIdAreaId& propIdAreaId) {
108     // Make a copy so that we don't modify 'mContSubConfigsByPropIdArea' on failure cases.
109     ContSubConfigs newConfig = mContSubConfigsByPropIdArea[propIdAreaId];
110     newConfig.removeClient(clientId);
111     return updateContSubConfigs(propIdAreaId, newConfig);
112 }
113 
updateContSubConfigs(const PropIdAreaId & propIdAreaId,const ContSubConfigs & newConfig)114 VhalResult<void> SubscriptionManager::updateContSubConfigs(const PropIdAreaId& propIdAreaId,
115                                                            const ContSubConfigs& newConfig) {
116     if (newConfig.getMaxSampleRateHz() ==
117         mContSubConfigsByPropIdArea[propIdAreaId].getMaxSampleRateHz()) {
118         mContSubConfigsByPropIdArea[propIdAreaId] = newConfig;
119         return {};
120     }
121     float newRateHz = newConfig.getMaxSampleRateHz();
122     int32_t propId = propIdAreaId.propId;
123     int32_t areaId = propIdAreaId.areaId;
124     if (auto status = mVehicleHardware->updateSampleRate(propId, areaId, newRateHz);
125         status != StatusCode::OK) {
126         return StatusError(status) << StringPrintf("failed to update sample rate for prop: %" PRId32
127                                                    ", area"
128                                                    ": %" PRId32 ", sample rate: %f HZ",
129                                                    propId, areaId, newRateHz);
130     }
131     mContSubConfigsByPropIdArea[propIdAreaId] = newConfig;
132     return {};
133 }
134 
subscribe(const std::shared_ptr<IVehicleCallback> & callback,const std::vector<SubscribeOptions> & options,bool isContinuousProperty)135 VhalResult<void> SubscriptionManager::subscribe(const std::shared_ptr<IVehicleCallback>& callback,
136                                                 const std::vector<SubscribeOptions>& options,
137                                                 bool isContinuousProperty) {
138     std::scoped_lock<std::mutex> lockGuard(mLock);
139 
140     for (const auto& option : options) {
141         float sampleRateHz = option.sampleRate;
142 
143         if (isContinuousProperty) {
144             if (auto result = getIntervalNanos(sampleRateHz); !result.ok()) {
145                 return StatusError(StatusCode::INVALID_ARG) << result.error().message();
146             }
147         }
148 
149         if (option.areaIds.empty()) {
150             ALOGE("area IDs to subscribe must not be empty");
151             return StatusError(StatusCode::INVALID_ARG)
152                    << "area IDs to subscribe must not be empty";
153         }
154     }
155 
156     ClientIdType clientId = callback->asBinder().get();
157 
158     for (const auto& option : options) {
159         int32_t propId = option.propId;
160         const std::vector<int32_t>& areaIds = option.areaIds;
161         for (int32_t areaId : areaIds) {
162             PropIdAreaId propIdAreaId = {
163                     .propId = propId,
164                     .areaId = areaId,
165             };
166             if (isContinuousProperty) {
167                 if (auto result = addContinuousSubscriberLocked(clientId, propIdAreaId,
168                                                                 option.sampleRate);
169                     !result.ok()) {
170                     return result;
171                 }
172             }
173 
174             mSubscribedPropsByClient[clientId].insert(propIdAreaId);
175             mClientsByPropIdArea[propIdAreaId][clientId] = callback;
176         }
177     }
178     return {};
179 }
180 
unsubscribe(SubscriptionManager::ClientIdType clientId,const std::vector<int32_t> & propIds)181 VhalResult<void> SubscriptionManager::unsubscribe(SubscriptionManager::ClientIdType clientId,
182                                                   const std::vector<int32_t>& propIds) {
183     std::scoped_lock<std::mutex> lockGuard(mLock);
184 
185     if (mSubscribedPropsByClient.find(clientId) == mSubscribedPropsByClient.end()) {
186         return StatusError(StatusCode::INVALID_ARG)
187                << "No property was subscribed for the callback";
188     }
189     std::unordered_set<int32_t> subscribedPropIds;
190     for (auto const& propIdAreaId : mSubscribedPropsByClient[clientId]) {
191         subscribedPropIds.insert(propIdAreaId.propId);
192     }
193 
194     for (int32_t propId : propIds) {
195         if (subscribedPropIds.find(propId) == subscribedPropIds.end()) {
196             return StatusError(StatusCode::INVALID_ARG)
197                    << "property ID: " << propId << " is not subscribed";
198         }
199     }
200 
201     auto& propIdAreaIds = mSubscribedPropsByClient[clientId];
202     auto it = propIdAreaIds.begin();
203     while (it != propIdAreaIds.end()) {
204         int32_t propId = it->propId;
205         if (std::find(propIds.begin(), propIds.end(), propId) != propIds.end()) {
206             if (auto result = removeContinuousSubscriberLocked(clientId, *it); !result.ok()) {
207                 return result;
208             }
209 
210             auto& clients = mClientsByPropIdArea[*it];
211             clients.erase(clientId);
212             if (clients.empty()) {
213                 mClientsByPropIdArea.erase(*it);
214                 mContSubConfigsByPropIdArea.erase(*it);
215             }
216             it = propIdAreaIds.erase(it);
217         } else {
218             it++;
219         }
220     }
221     if (propIdAreaIds.empty()) {
222         mSubscribedPropsByClient.erase(clientId);
223     }
224     return {};
225 }
226 
unsubscribe(SubscriptionManager::ClientIdType clientId)227 VhalResult<void> SubscriptionManager::unsubscribe(SubscriptionManager::ClientIdType clientId) {
228     std::scoped_lock<std::mutex> lockGuard(mLock);
229 
230     if (mSubscribedPropsByClient.find(clientId) == mSubscribedPropsByClient.end()) {
231         return StatusError(StatusCode::INVALID_ARG) << "No property was subscribed for this client";
232     }
233 
234     auto& subscriptions = mSubscribedPropsByClient[clientId];
235     for (auto const& propIdAreaId : subscriptions) {
236         if (auto result = removeContinuousSubscriberLocked(clientId, propIdAreaId); !result.ok()) {
237             return result;
238         }
239 
240         auto& clients = mClientsByPropIdArea[propIdAreaId];
241         clients.erase(clientId);
242         if (clients.empty()) {
243             mClientsByPropIdArea.erase(propIdAreaId);
244             mContSubConfigsByPropIdArea.erase(propIdAreaId);
245         }
246     }
247     mSubscribedPropsByClient.erase(clientId);
248     return {};
249 }
250 
251 std::unordered_map<std::shared_ptr<IVehicleCallback>, std::vector<const VehiclePropValue*>>
getSubscribedClients(const std::vector<VehiclePropValue> & updatedValues)252 SubscriptionManager::getSubscribedClients(const std::vector<VehiclePropValue>& updatedValues) {
253     std::scoped_lock<std::mutex> lockGuard(mLock);
254     std::unordered_map<std::shared_ptr<IVehicleCallback>, std::vector<const VehiclePropValue*>>
255             clients;
256 
257     for (const auto& value : updatedValues) {
258         PropIdAreaId propIdAreaId{
259                 .propId = value.prop,
260                 .areaId = value.areaId,
261         };
262         if (mClientsByPropIdArea.find(propIdAreaId) == mClientsByPropIdArea.end()) {
263             continue;
264         }
265 
266         for (const auto& [_, client] : mClientsByPropIdArea[propIdAreaId]) {
267             clients[client].push_back(&value);
268         }
269     }
270     return clients;
271 }
272 
273 std::unordered_map<std::shared_ptr<IVehicleCallback>, std::vector<VehiclePropError>>
getSubscribedClientsForErrorEvents(const std::vector<SetValueErrorEvent> & errorEvents)274 SubscriptionManager::getSubscribedClientsForErrorEvents(
275         const std::vector<SetValueErrorEvent>& errorEvents) {
276     std::scoped_lock<std::mutex> lockGuard(mLock);
277     std::unordered_map<std::shared_ptr<IVehicleCallback>, std::vector<VehiclePropError>> clients;
278 
279     for (const auto& errorEvent : errorEvents) {
280         PropIdAreaId propIdAreaId{
281                 .propId = errorEvent.propId,
282                 .areaId = errorEvent.areaId,
283         };
284         if (mClientsByPropIdArea.find(propIdAreaId) == mClientsByPropIdArea.end()) {
285             continue;
286         }
287 
288         for (const auto& [_, client] : mClientsByPropIdArea[propIdAreaId]) {
289             clients[client].push_back({
290                     .propId = errorEvent.propId,
291                     .areaId = errorEvent.areaId,
292                     .errorCode = errorEvent.errorCode,
293             });
294         }
295     }
296     return clients;
297 }
298 
isEmpty()299 bool SubscriptionManager::isEmpty() {
300     std::scoped_lock<std::mutex> lockGuard(mLock);
301     return mSubscribedPropsByClient.empty() && mClientsByPropIdArea.empty();
302 }
303 
304 }  // namespace vehicle
305 }  // namespace automotive
306 }  // namespace hardware
307 }  // namespace android
308