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