• 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 
20 #include "VehiclePropertyStore.h"
21 
22 #include <VehicleHalTypes.h>
23 #include <VehicleUtils.h>
24 #include <android-base/stringprintf.h>
25 #include <math/HashCombine.h>
26 
27 #include <inttypes.h>
28 
29 namespace android {
30 namespace hardware {
31 namespace automotive {
32 namespace vehicle {
33 
34 using ::aidl::android::hardware::automotive::vehicle::StatusCode;
35 using ::aidl::android::hardware::automotive::vehicle::VehicleAreaConfig;
36 using ::aidl::android::hardware::automotive::vehicle::VehiclePropConfig;
37 using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyStatus;
38 using ::aidl::android::hardware::automotive::vehicle::VehiclePropValue;
39 using ::android::base::Result;
40 using ::android::base::StringPrintf;
41 
operator ==(const VehiclePropertyStore::RecordId & other) const42 bool VehiclePropertyStore::RecordId::operator==(const VehiclePropertyStore::RecordId& other) const {
43     return area == other.area && token == other.token;
44 }
45 
toString() const46 std::string VehiclePropertyStore::RecordId::toString() const {
47     return StringPrintf("RecordID{{.areaId=% " PRId32 ", .token=%" PRId64 "}", area, token);
48 }
49 
operator ()(RecordId const & recordId) const50 size_t VehiclePropertyStore::RecordIdHash::operator()(RecordId const& recordId) const {
51     size_t res = 0;
52     hashCombine(res, recordId.area);
53     hashCombine(res, recordId.token);
54     return res;
55 }
56 
~VehiclePropertyStore()57 VehiclePropertyStore::~VehiclePropertyStore() {
58     std::scoped_lock<std::mutex> lockGuard(mLock);
59 
60     // Recycling record requires mValuePool, so need to recycle them before destroying mValuePool.
61     mRecordsByPropId.clear();
62     mValuePool.reset();
63 }
64 
getRecordLocked(int32_t propId) const65 const VehiclePropertyStore::Record* VehiclePropertyStore::getRecordLocked(int32_t propId) const
66         REQUIRES(mLock) {
67     auto RecordIt = mRecordsByPropId.find(propId);
68     return RecordIt == mRecordsByPropId.end() ? nullptr : &RecordIt->second;
69 }
70 
getRecordLocked(int32_t propId)71 VehiclePropertyStore::Record* VehiclePropertyStore::getRecordLocked(int32_t propId)
72         REQUIRES(mLock) {
73     auto RecordIt = mRecordsByPropId.find(propId);
74     return RecordIt == mRecordsByPropId.end() ? nullptr : &RecordIt->second;
75 }
76 
getRecordIdLocked(const VehiclePropValue & propValue,const VehiclePropertyStore::Record & record) const77 VehiclePropertyStore::RecordId VehiclePropertyStore::getRecordIdLocked(
78         const VehiclePropValue& propValue, const VehiclePropertyStore::Record& record) const
79         REQUIRES(mLock) {
80     VehiclePropertyStore::RecordId recId{
81             .area = isGlobalProp(propValue.prop) ? 0 : propValue.areaId, .token = 0};
82 
83     if (record.tokenFunction != nullptr) {
84         recId.token = record.tokenFunction(propValue);
85     }
86     return recId;
87 }
88 
readValueLocked(const RecordId & recId,const Record & record) const89 VhalResult<VehiclePropValuePool::RecyclableType> VehiclePropertyStore::readValueLocked(
90         const RecordId& recId, const Record& record) const REQUIRES(mLock) {
91     if (auto it = record.values.find(recId); it != record.values.end()) {
92         return mValuePool->obtain(*(it->second));
93     }
94     return StatusError(StatusCode::NOT_AVAILABLE)
95            << "Record ID: " << recId.toString() << " is not found";
96 }
97 
registerProperty(const VehiclePropConfig & config,VehiclePropertyStore::TokenFunction tokenFunc)98 void VehiclePropertyStore::registerProperty(const VehiclePropConfig& config,
99                                             VehiclePropertyStore::TokenFunction tokenFunc) {
100     std::scoped_lock<std::mutex> g(mLock);
101 
102     mRecordsByPropId[config.prop] = Record{
103             .propConfig = config,
104             .tokenFunction = tokenFunc,
105     };
106 }
107 
writeValue(VehiclePropValuePool::RecyclableType propValue,bool updateStatus,VehiclePropertyStore::EventMode eventMode)108 VhalResult<void> VehiclePropertyStore::writeValue(VehiclePropValuePool::RecyclableType propValue,
109                                                   bool updateStatus,
110                                                   VehiclePropertyStore::EventMode eventMode) {
111     std::scoped_lock<std::mutex> g(mLock);
112 
113     int32_t propId = propValue->prop;
114 
115     VehiclePropertyStore::Record* record = getRecordLocked(propId);
116     if (record == nullptr) {
117         return StatusError(StatusCode::INVALID_ARG) << "property: " << propId << " not registered";
118     }
119 
120     if (!isGlobalProp(propId) && getAreaConfig(*propValue, record->propConfig) == nullptr) {
121         return StatusError(StatusCode::INVALID_ARG)
122                << "no config for property: " << propId << " area: " << propValue->areaId;
123     }
124 
125     VehiclePropertyStore::RecordId recId = getRecordIdLocked(*propValue, *record);
126     bool valueUpdated = true;
127     if (auto it = record->values.find(recId); it != record->values.end()) {
128         const VehiclePropValue* valueToUpdate = it->second.get();
129         int64_t oldTimestamp = valueToUpdate->timestamp;
130         VehiclePropertyStatus oldStatus = valueToUpdate->status;
131         // propValue is outdated and drops it.
132         if (oldTimestamp > propValue->timestamp) {
133             return StatusError(StatusCode::INVALID_ARG)
134                    << "outdated timestamp: " << propValue->timestamp;
135         }
136         if (!updateStatus) {
137             propValue->status = oldStatus;
138         }
139 
140         valueUpdated = (valueToUpdate->value != propValue->value ||
141                         valueToUpdate->status != propValue->status ||
142                         valueToUpdate->prop != propValue->prop ||
143                         valueToUpdate->areaId != propValue->areaId);
144     } else if (!updateStatus) {
145         propValue->status = VehiclePropertyStatus::AVAILABLE;
146     }
147 
148     record->values[recId] = std::move(propValue);
149 
150     if (eventMode == EventMode::NEVER) {
151         return {};
152     }
153 
154     if ((eventMode == EventMode::ALWAYS || valueUpdated) && mOnValueChangeCallback != nullptr) {
155         mOnValueChangeCallback(*(record->values[recId]));
156     }
157     return {};
158 }
159 
removeValue(const VehiclePropValue & propValue)160 void VehiclePropertyStore::removeValue(const VehiclePropValue& propValue) {
161     std::scoped_lock<std::mutex> g(mLock);
162 
163     VehiclePropertyStore::Record* record = getRecordLocked(propValue.prop);
164     if (record == nullptr) {
165         return;
166     }
167 
168     VehiclePropertyStore::RecordId recId = getRecordIdLocked(propValue, *record);
169     if (auto it = record->values.find(recId); it != record->values.end()) {
170         record->values.erase(it);
171     }
172 }
173 
removeValuesForProperty(int32_t propId)174 void VehiclePropertyStore::removeValuesForProperty(int32_t propId) {
175     std::scoped_lock<std::mutex> g(mLock);
176 
177     VehiclePropertyStore::Record* record = getRecordLocked(propId);
178     if (record == nullptr) {
179         return;
180     }
181 
182     record->values.clear();
183 }
184 
readAllValues() const185 std::vector<VehiclePropValuePool::RecyclableType> VehiclePropertyStore::readAllValues() const {
186     std::scoped_lock<std::mutex> g(mLock);
187 
188     std::vector<VehiclePropValuePool::RecyclableType> allValues;
189 
190     for (auto const& [_, record] : mRecordsByPropId) {
191         for (auto const& [_, value] : record.values) {
192             allValues.push_back(std::move(mValuePool->obtain(*value)));
193         }
194     }
195 
196     return allValues;
197 }
198 
readValuesForProperty(int32_t propId) const199 VehiclePropertyStore::ValuesResultType VehiclePropertyStore::readValuesForProperty(
200         int32_t propId) const {
201     std::scoped_lock<std::mutex> g(mLock);
202 
203     std::vector<VehiclePropValuePool::RecyclableType> values;
204 
205     const VehiclePropertyStore::Record* record = getRecordLocked(propId);
206     if (record == nullptr) {
207         return StatusError(StatusCode::INVALID_ARG) << "property: " << propId << " not registered";
208     }
209 
210     for (auto const& [_, value] : record->values) {
211         values.push_back(std::move(mValuePool->obtain(*value)));
212     }
213     return values;
214 }
215 
readValue(const VehiclePropValue & propValue) const216 VehiclePropertyStore::ValueResultType VehiclePropertyStore::readValue(
217         const VehiclePropValue& propValue) const {
218     std::scoped_lock<std::mutex> g(mLock);
219 
220     int32_t propId = propValue.prop;
221     const VehiclePropertyStore::Record* record = getRecordLocked(propId);
222     if (record == nullptr) {
223         return StatusError(StatusCode::INVALID_ARG) << "property: " << propId << " not registered";
224     }
225 
226     VehiclePropertyStore::RecordId recId = getRecordIdLocked(propValue, *record);
227     return readValueLocked(recId, *record);
228 }
229 
readValue(int32_t propId,int32_t areaId,int64_t token) const230 VehiclePropertyStore::ValueResultType VehiclePropertyStore::readValue(int32_t propId,
231                                                                       int32_t areaId,
232                                                                       int64_t token) const {
233     std::scoped_lock<std::mutex> g(mLock);
234 
235     const VehiclePropertyStore::Record* record = getRecordLocked(propId);
236     if (record == nullptr) {
237         return StatusError(StatusCode::INVALID_ARG) << "property: " << propId << " not registered";
238     }
239 
240     VehiclePropertyStore::RecordId recId{.area = isGlobalProp(propId) ? 0 : areaId, .token = token};
241     return readValueLocked(recId, *record);
242 }
243 
getAllConfigs() const244 std::vector<VehiclePropConfig> VehiclePropertyStore::getAllConfigs() const {
245     std::scoped_lock<std::mutex> g(mLock);
246 
247     std::vector<VehiclePropConfig> configs;
248     configs.reserve(mRecordsByPropId.size());
249     for (auto& [_, config] : mRecordsByPropId) {
250         configs.push_back(config.propConfig);
251     }
252     return configs;
253 }
254 
getConfig(int32_t propId) const255 VhalResult<const VehiclePropConfig*> VehiclePropertyStore::getConfig(int32_t propId) const {
256     std::scoped_lock<std::mutex> g(mLock);
257 
258     const VehiclePropertyStore::Record* record = getRecordLocked(propId);
259     if (record == nullptr) {
260         return StatusError(StatusCode::INVALID_ARG) << "property: " << propId << " not registered";
261     }
262 
263     return &record->propConfig;
264 }
265 
setOnValueChangeCallback(const VehiclePropertyStore::OnValueChangeCallback & callback)266 void VehiclePropertyStore::setOnValueChangeCallback(
267         const VehiclePropertyStore::OnValueChangeCallback& callback) {
268     std::scoped_lock<std::mutex> g(mLock);
269 
270     mOnValueChangeCallback = callback;
271 }
272 
273 }  // namespace vehicle
274 }  // namespace automotive
275 }  // namespace hardware
276 }  // namespace android
277