• 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 #define LOG_TAG "VehiclePropertyStore"
18 #include <utils/Log.h>
19 #include <utils/SystemClock.h>
20 
21 #include "VehiclePropertyStore.h"
22 
23 #include <VehicleHalTypes.h>
24 #include <VehicleUtils.h>
25 #include <android-base/stringprintf.h>
26 #include <math/HashCombine.h>
27 
28 #include <inttypes.h>
29 
30 namespace android {
31 namespace hardware {
32 namespace automotive {
33 namespace vehicle {
34 
35 using ::aidl::android::hardware::automotive::vehicle::StatusCode;
36 using ::aidl::android::hardware::automotive::vehicle::VehicleAreaConfig;
37 using ::aidl::android::hardware::automotive::vehicle::VehiclePropConfig;
38 using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyStatus;
39 using ::aidl::android::hardware::automotive::vehicle::VehiclePropValue;
40 using ::android::base::Result;
41 using ::android::base::StringPrintf;
42 
operator ==(const VehiclePropertyStore::RecordId & other) const43 bool VehiclePropertyStore::RecordId::operator==(const VehiclePropertyStore::RecordId& other) const {
44     return area == other.area && token == other.token;
45 }
46 
toString() const47 std::string VehiclePropertyStore::RecordId::toString() const {
48     return StringPrintf("RecordID{{.areaId=% " PRId32 ", .token=%" PRId64 "}", area, token);
49 }
50 
operator ()(RecordId const & recordId) const51 size_t VehiclePropertyStore::RecordIdHash::operator()(RecordId const& recordId) const {
52     size_t res = 0;
53     hashCombine(res, recordId.area);
54     hashCombine(res, recordId.token);
55     return res;
56 }
57 
~VehiclePropertyStore()58 VehiclePropertyStore::~VehiclePropertyStore() {
59     std::scoped_lock<std::mutex> lockGuard(mLock);
60 
61     // Recycling record requires mValuePool, so need to recycle them before destroying mValuePool.
62     mRecordsByPropId.clear();
63     mValuePool.reset();
64 }
65 
getRecordLocked(int32_t propId) const66 const VehiclePropertyStore::Record* VehiclePropertyStore::getRecordLocked(int32_t propId) const
67         REQUIRES(mLock) {
68     auto RecordIt = mRecordsByPropId.find(propId);
69     return RecordIt == mRecordsByPropId.end() ? nullptr : &RecordIt->second;
70 }
71 
getRecordLocked(int32_t propId)72 VehiclePropertyStore::Record* VehiclePropertyStore::getRecordLocked(int32_t propId)
73         REQUIRES(mLock) {
74     auto RecordIt = mRecordsByPropId.find(propId);
75     return RecordIt == mRecordsByPropId.end() ? nullptr : &RecordIt->second;
76 }
77 
getRecordIdLocked(const VehiclePropValue & propValue,const VehiclePropertyStore::Record & record) const78 VehiclePropertyStore::RecordId VehiclePropertyStore::getRecordIdLocked(
79         const VehiclePropValue& propValue, const VehiclePropertyStore::Record& record) const
80         REQUIRES(mLock) {
81     VehiclePropertyStore::RecordId recId{
82             .area = isGlobalProp(propValue.prop) ? 0 : propValue.areaId, .token = 0};
83 
84     if (record.tokenFunction != nullptr) {
85         recId.token = record.tokenFunction(propValue);
86     }
87     return recId;
88 }
89 
readValueLocked(const RecordId & recId,const Record & record) const90 VhalResult<VehiclePropValuePool::RecyclableType> VehiclePropertyStore::readValueLocked(
91         const RecordId& recId, const Record& record) const REQUIRES(mLock) {
92     if (auto it = record.values.find(recId); it != record.values.end()) {
93         return mValuePool->obtain(*(it->second));
94     }
95     return StatusError(StatusCode::NOT_AVAILABLE)
96            << "Record ID: " << recId.toString() << " is not found";
97 }
98 
registerProperty(const VehiclePropConfig & config,VehiclePropertyStore::TokenFunction tokenFunc)99 void VehiclePropertyStore::registerProperty(const VehiclePropConfig& config,
100                                             VehiclePropertyStore::TokenFunction tokenFunc) {
101     std::scoped_lock<std::mutex> g(mLock);
102 
103     mRecordsByPropId[config.prop] = Record{
104             .propConfig = config,
105             .tokenFunction = tokenFunc,
106     };
107 }
108 
writeValue(VehiclePropValuePool::RecyclableType propValue,bool updateStatus,VehiclePropertyStore::EventMode eventMode,bool useCurrentTimestamp)109 VhalResult<void> VehiclePropertyStore::writeValue(VehiclePropValuePool::RecyclableType propValue,
110                                                   bool updateStatus,
111                                                   VehiclePropertyStore::EventMode eventMode,
112                                                   bool useCurrentTimestamp) {
113     bool valueUpdated = true;
114     VehiclePropValue updatedValue;
115     OnValueChangeCallback onValueChangeCallback = nullptr;
116     OnValuesChangeCallback onValuesChangeCallback = nullptr;
117     int32_t propId;
118     int32_t areaId;
119     {
120         std::scoped_lock<std::mutex> g(mLock);
121 
122         // Must set timestamp inside the lock to make sure no other writeValue will update the
123         // the timestamp to a newer one while we are writing this value.
124         if (useCurrentTimestamp) {
125             propValue->timestamp = elapsedRealtimeNano();
126         }
127 
128         propId = propValue->prop;
129         areaId = propValue->areaId;
130 
131         VehiclePropertyStore::Record* record = getRecordLocked(propId);
132         if (record == nullptr) {
133             return StatusError(StatusCode::INVALID_ARG)
134                    << "property: " << propId << " not registered";
135         }
136 
137         if (!isGlobalProp(propId) && getAreaConfig(*propValue, record->propConfig) == nullptr) {
138             return StatusError(StatusCode::INVALID_ARG)
139                    << "no config for property: " << propId << " area ID: " << propValue->areaId;
140         }
141 
142         VehiclePropertyStore::RecordId recId = getRecordIdLocked(*propValue, *record);
143         if (auto it = record->values.find(recId); it != record->values.end()) {
144             const VehiclePropValue* valueToUpdate = it->second.get();
145             int64_t oldTimestampNanos = valueToUpdate->timestamp;
146             VehiclePropertyStatus oldStatus = valueToUpdate->status;
147             // propValue is outdated and drops it.
148             if (oldTimestampNanos > propValue->timestamp) {
149                 return StatusError(StatusCode::INVALID_ARG)
150                        << "outdated timestampNanos: " << propValue->timestamp;
151             }
152             if (!updateStatus) {
153                 propValue->status = oldStatus;
154             }
155 
156             // areaId and propId must be the same between valueToUpdate and propValue.
157             valueUpdated = (valueToUpdate->value != propValue->value ||
158                             valueToUpdate->status != propValue->status);
159         } else if (!updateStatus) {
160             propValue->status = VehiclePropertyStatus::AVAILABLE;
161         }
162 
163         record->values[recId] = std::move(propValue);
164 
165         if (eventMode == EventMode::NEVER) {
166             return {};
167         }
168         updatedValue = *(record->values[recId]);
169 
170         onValuesChangeCallback = mOnValuesChangeCallback;
171         onValueChangeCallback = mOnValueChangeCallback;
172     }
173 
174     if (onValuesChangeCallback == nullptr && onValueChangeCallback == nullptr) {
175         // No callback registered.
176         return {};
177     }
178 
179     // Invoke the callback outside the lock to prevent dead-lock.
180     if (eventMode == EventMode::ALWAYS || valueUpdated) {
181         if (onValuesChangeCallback != nullptr) {
182             onValuesChangeCallback({updatedValue});
183         } else {
184             onValueChangeCallback(updatedValue);
185         }
186     }
187     return {};
188 }
189 
refreshTimestamp(int32_t propId,int32_t areaId,EventMode eventMode)190 void VehiclePropertyStore::refreshTimestamp(int32_t propId, int32_t areaId, EventMode eventMode) {
191     std::unordered_map<PropIdAreaId, EventMode, PropIdAreaIdHash> eventModeByPropIdAreaId;
192     PropIdAreaId propIdAreaId = {
193             .propId = propId,
194             .areaId = areaId,
195     };
196     eventModeByPropIdAreaId[propIdAreaId] = eventMode;
197     refreshTimestamps(eventModeByPropIdAreaId);
198 }
199 
refreshTimestamps(std::unordered_map<PropIdAreaId,EventMode,PropIdAreaIdHash> eventModeByPropIdAreaId)200 void VehiclePropertyStore::refreshTimestamps(
201         std::unordered_map<PropIdAreaId, EventMode, PropIdAreaIdHash> eventModeByPropIdAreaId) {
202     std::vector<VehiclePropValue> updatedValues;
203     OnValuesChangeCallback onValuesChangeCallback = nullptr;
204     OnValueChangeCallback onValueChangeCallback = nullptr;
205     {
206         std::scoped_lock<std::mutex> g(mLock);
207 
208         onValuesChangeCallback = mOnValuesChangeCallback;
209         onValueChangeCallback = mOnValueChangeCallback;
210 
211         for (const auto& [propIdAreaId, eventMode] : eventModeByPropIdAreaId) {
212             int32_t propId = propIdAreaId.propId;
213             int32_t areaId = propIdAreaId.areaId;
214             VehiclePropertyStore::Record* record = getRecordLocked(propId);
215             if (record == nullptr) {
216                 continue;
217             }
218 
219             VehiclePropValue propValue = {
220                     .areaId = areaId,
221                     .prop = propId,
222                     .value = {},
223             };
224 
225             VehiclePropertyStore::RecordId recId = getRecordIdLocked(propValue, *record);
226             if (auto it = record->values.find(recId); it != record->values.end()) {
227                 it->second->timestamp = elapsedRealtimeNano();
228                 if (eventMode == EventMode::ALWAYS) {
229                     updatedValues.push_back(*(it->second));
230                 }
231             } else {
232                 continue;
233             }
234         }
235     }
236 
237     // Invoke the callback outside the lock to prevent dead-lock.
238     if (updatedValues.empty()) {
239         return;
240     }
241     if (!onValuesChangeCallback && !onValueChangeCallback) {
242         // If no callback is set, then we don't have to do anything.
243         for (const auto& updateValue : updatedValues) {
244             ALOGW("No callback registered, ignoring property update for propId: %" PRId32
245                   ", area ID: %" PRId32,
246                   updateValue.prop, updateValue.areaId);
247         }
248         return;
249     }
250     if (onValuesChangeCallback != nullptr) {
251         onValuesChangeCallback(updatedValues);
252     } else {
253         // Fallback to use multiple onValueChangeCallback
254         for (const auto& updateValue : updatedValues) {
255             onValueChangeCallback(updateValue);
256         }
257     }
258 }
259 
removeValue(const VehiclePropValue & propValue)260 void VehiclePropertyStore::removeValue(const VehiclePropValue& propValue) {
261     std::scoped_lock<std::mutex> g(mLock);
262 
263     VehiclePropertyStore::Record* record = getRecordLocked(propValue.prop);
264     if (record == nullptr) {
265         return;
266     }
267 
268     VehiclePropertyStore::RecordId recId = getRecordIdLocked(propValue, *record);
269     if (auto it = record->values.find(recId); it != record->values.end()) {
270         record->values.erase(it);
271     }
272 }
273 
removeValuesForProperty(int32_t propId)274 void VehiclePropertyStore::removeValuesForProperty(int32_t propId) {
275     std::scoped_lock<std::mutex> g(mLock);
276 
277     VehiclePropertyStore::Record* record = getRecordLocked(propId);
278     if (record == nullptr) {
279         return;
280     }
281 
282     record->values.clear();
283 }
284 
readAllValues() const285 std::vector<VehiclePropValuePool::RecyclableType> VehiclePropertyStore::readAllValues() const {
286     std::scoped_lock<std::mutex> g(mLock);
287 
288     std::vector<VehiclePropValuePool::RecyclableType> allValues;
289 
290     for (auto const& [_, record] : mRecordsByPropId) {
291         for (auto const& [_, value] : record.values) {
292             allValues.push_back(std::move(mValuePool->obtain(*value)));
293         }
294     }
295 
296     return allValues;
297 }
298 
readValuesForProperty(int32_t propId) const299 VehiclePropertyStore::ValuesResultType VehiclePropertyStore::readValuesForProperty(
300         int32_t propId) const {
301     std::scoped_lock<std::mutex> g(mLock);
302 
303     std::vector<VehiclePropValuePool::RecyclableType> values;
304 
305     const VehiclePropertyStore::Record* record = getRecordLocked(propId);
306     if (record == nullptr) {
307         return StatusError(StatusCode::INVALID_ARG) << "property: " << propId << " not registered";
308     }
309 
310     for (auto const& [_, value] : record->values) {
311         values.push_back(std::move(mValuePool->obtain(*value)));
312     }
313     return values;
314 }
315 
readValue(const VehiclePropValue & propValue) const316 VehiclePropertyStore::ValueResultType VehiclePropertyStore::readValue(
317         const VehiclePropValue& propValue) const {
318     std::scoped_lock<std::mutex> g(mLock);
319 
320     int32_t propId = propValue.prop;
321     const VehiclePropertyStore::Record* record = getRecordLocked(propId);
322     if (record == nullptr) {
323         return StatusError(StatusCode::INVALID_ARG) << "property: " << propId << " not registered";
324     }
325 
326     VehiclePropertyStore::RecordId recId = getRecordIdLocked(propValue, *record);
327     return readValueLocked(recId, *record);
328 }
329 
readValue(int32_t propId,int32_t areaId,int64_t token) const330 VehiclePropertyStore::ValueResultType VehiclePropertyStore::readValue(int32_t propId,
331                                                                       int32_t areaId,
332                                                                       int64_t token) const {
333     std::scoped_lock<std::mutex> g(mLock);
334 
335     const VehiclePropertyStore::Record* record = getRecordLocked(propId);
336     if (record == nullptr) {
337         return StatusError(StatusCode::INVALID_ARG) << "property: " << propId << " not registered";
338     }
339 
340     VehiclePropertyStore::RecordId recId{.area = isGlobalProp(propId) ? 0 : areaId, .token = token};
341     return readValueLocked(recId, *record);
342 }
343 
getAllConfigs() const344 std::vector<VehiclePropConfig> VehiclePropertyStore::getAllConfigs() const {
345     std::scoped_lock<std::mutex> g(mLock);
346 
347     std::vector<VehiclePropConfig> configs;
348     configs.reserve(mRecordsByPropId.size());
349     for (auto& [_, config] : mRecordsByPropId) {
350         configs.push_back(config.propConfig);
351     }
352     return configs;
353 }
354 
getConfig(int32_t propId) const355 VhalResult<const VehiclePropConfig*> VehiclePropertyStore::getConfig(int32_t propId) const {
356     std::scoped_lock<std::mutex> g(mLock);
357 
358     const VehiclePropertyStore::Record* record = getRecordLocked(propId);
359     if (record == nullptr) {
360         return StatusError(StatusCode::INVALID_ARG) << "property: " << propId << " not registered";
361     }
362 
363     return &record->propConfig;
364 }
365 
getPropConfig(int32_t propId) const366 VhalResult<VehiclePropConfig> VehiclePropertyStore::getPropConfig(int32_t propId) const {
367     std::scoped_lock<std::mutex> g(mLock);
368 
369     const VehiclePropertyStore::Record* record = getRecordLocked(propId);
370     if (record == nullptr) {
371         return StatusError(StatusCode::INVALID_ARG) << "property: " << propId << " not registered";
372     }
373 
374     return record->propConfig;
375 }
376 
setOnValueChangeCallback(const VehiclePropertyStore::OnValueChangeCallback & callback)377 void VehiclePropertyStore::setOnValueChangeCallback(
378         const VehiclePropertyStore::OnValueChangeCallback& callback) {
379     std::scoped_lock<std::mutex> g(mLock);
380 
381     mOnValueChangeCallback = callback;
382 }
383 
setOnValuesChangeCallback(const VehiclePropertyStore::OnValuesChangeCallback & callback)384 void VehiclePropertyStore::setOnValuesChangeCallback(
385         const VehiclePropertyStore::OnValuesChangeCallback& callback) {
386     std::scoped_lock<std::mutex> g(mLock);
387 
388     mOnValuesChangeCallback = callback;
389 }
390 
391 }  // namespace vehicle
392 }  // namespace automotive
393 }  // namespace hardware
394 }  // namespace android
395