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 "VehicleHalManager.h"
20
21 #include <cmath>
22 #include <fstream>
23
24 #include <android/log.h>
25 #include <android/hardware/automotive/vehicle/2.0/BpHwVehicleCallback.h>
26
27 #include "VehicleUtils.h"
28
29 namespace android {
30 namespace hardware {
31 namespace automotive {
32 namespace vehicle {
33 namespace V2_0 {
34
35 using namespace std::placeholders;
36
37 constexpr std::chrono::milliseconds kHalEventBatchingTimeWindow(10);
38
39 const VehiclePropValue kEmptyValue{};
40
41 /**
42 * Indicates what's the maximum size of hidl_vec<VehiclePropValue> we want
43 * to store in reusable object pool.
44 */
45 constexpr auto kMaxHidlVecOfVehiclPropValuePoolSize = 20;
46
getAllPropConfigs(getAllPropConfigs_cb _hidl_cb)47 Return<void> VehicleHalManager::getAllPropConfigs(getAllPropConfigs_cb _hidl_cb) {
48 ALOGI("getAllPropConfigs called");
49 hidl_vec<VehiclePropConfig> hidlConfigs;
50 auto& halConfig = mConfigIndex->getAllConfigs();
51
52 hidlConfigs.setToExternal(
53 const_cast<VehiclePropConfig *>(halConfig.data()),
54 halConfig.size());
55
56 _hidl_cb(hidlConfigs);
57
58 return Void();
59 }
60
getPropConfigs(const hidl_vec<int32_t> & properties,getPropConfigs_cb _hidl_cb)61 Return<void> VehicleHalManager::getPropConfigs(const hidl_vec<int32_t> &properties,
62 getPropConfigs_cb _hidl_cb) {
63 std::vector<VehiclePropConfig> configs;
64 for (size_t i = 0; i < properties.size(); i++) {
65 auto prop = properties[i];
66 if (mConfigIndex->hasConfig(prop)) {
67 configs.push_back(mConfigIndex->getConfig(prop));
68 } else {
69 ALOGW("Requested config for undefined property: 0x%x", prop);
70 _hidl_cb(StatusCode::INVALID_ARG, hidl_vec<VehiclePropConfig>());
71 }
72 }
73
74 _hidl_cb(StatusCode::OK, configs);
75
76 return Void();
77 }
78
get(const VehiclePropValue & requestedPropValue,get_cb _hidl_cb)79 Return<void> VehicleHalManager::get(const VehiclePropValue& requestedPropValue, get_cb _hidl_cb) {
80 const auto* config = getPropConfigOrNull(requestedPropValue.prop);
81 if (config == nullptr) {
82 ALOGE("Failed to get value: config not found, property: 0x%x",
83 requestedPropValue.prop);
84 _hidl_cb(StatusCode::INVALID_ARG, kEmptyValue);
85 return Void();
86 }
87
88 if (!checkReadPermission(*config)) {
89 _hidl_cb(StatusCode::ACCESS_DENIED, kEmptyValue);
90 return Void();
91 }
92
93 StatusCode status;
94 auto value = mHal->get(requestedPropValue, &status);
95 _hidl_cb(status, value.get() ? *value : kEmptyValue);
96
97
98 return Void();
99 }
100
set(const VehiclePropValue & value)101 Return<StatusCode> VehicleHalManager::set(const VehiclePropValue &value) {
102 auto prop = value.prop;
103 const auto* config = getPropConfigOrNull(prop);
104 if (config == nullptr) {
105 ALOGE("Failed to set value: config not found, property: 0x%x", prop);
106 return StatusCode::INVALID_ARG;
107 }
108
109 if (!checkWritePermission(*config)) {
110 return StatusCode::ACCESS_DENIED;
111 }
112
113 handlePropertySetEvent(value);
114
115 auto status = mHal->set(value);
116
117 return Return<StatusCode>(status);
118 }
119
subscribe(const sp<IVehicleCallback> & callback,const hidl_vec<SubscribeOptions> & options)120 Return<StatusCode> VehicleHalManager::subscribe(const sp<IVehicleCallback> &callback,
121 const hidl_vec<SubscribeOptions> &options) {
122 hidl_vec<SubscribeOptions> verifiedOptions(options);
123 for (size_t i = 0; i < verifiedOptions.size(); i++) {
124 SubscribeOptions& ops = verifiedOptions[i];
125 auto prop = ops.propId;
126
127 const auto* config = getPropConfigOrNull(prop);
128 if (config == nullptr) {
129 ALOGE("Failed to subscribe: config not found, property: 0x%x",
130 prop);
131 return StatusCode::INVALID_ARG;
132 }
133
134 if (ops.flags == SubscribeFlags::UNDEFINED) {
135 ALOGE("Failed to subscribe: undefined flag in options provided");
136 return StatusCode::INVALID_ARG;
137 }
138
139 if (!isSubscribable(*config, ops.flags)) {
140 ALOGE("Failed to subscribe: property 0x%x is not subscribable",
141 prop);
142 return StatusCode::INVALID_ARG;
143 }
144
145 ops.sampleRate = checkSampleRate(*config, ops.sampleRate);
146 }
147
148 std::list<SubscribeOptions> updatedOptions;
149 auto res = mSubscriptionManager.addOrUpdateSubscription(getClientId(callback),
150 callback, verifiedOptions,
151 &updatedOptions);
152 if (StatusCode::OK != res) {
153 ALOGW("%s failed to subscribe, error code: %d", __func__, res);
154 return res;
155 }
156
157 for (auto opt : updatedOptions) {
158 mHal->subscribe(opt.propId, opt.sampleRate);
159 }
160
161 return StatusCode::OK;
162 }
163
unsubscribe(const sp<IVehicleCallback> & callback,int32_t propId)164 Return<StatusCode> VehicleHalManager::unsubscribe(const sp<IVehicleCallback>& callback,
165 int32_t propId) {
166 mSubscriptionManager.unsubscribe(getClientId(callback), propId);
167 return StatusCode::OK;
168 }
169
debugDump(IVehicle::debugDump_cb _hidl_cb)170 Return<void> VehicleHalManager::debugDump(IVehicle::debugDump_cb _hidl_cb) {
171 _hidl_cb("");
172 return Void();
173 }
174
init()175 void VehicleHalManager::init() {
176 ALOGI("VehicleHalManager::init");
177
178 mHidlVecOfVehiclePropValuePool.resize(kMaxHidlVecOfVehiclPropValuePoolSize);
179
180
181 mBatchingConsumer.run(&mEventQueue,
182 kHalEventBatchingTimeWindow,
183 std::bind(&VehicleHalManager::onBatchHalEvent,
184 this, _1));
185
186 mHal->init(&mValueObjectPool,
187 std::bind(&VehicleHalManager::onHalEvent, this, _1),
188 std::bind(&VehicleHalManager::onHalPropertySetError, this,
189 _1, _2, _3));
190
191 // Initialize index with vehicle configurations received from VehicleHal.
192 auto supportedPropConfigs = mHal->listProperties();
193 mConfigIndex.reset(new VehiclePropConfigIndex(supportedPropConfigs));
194
195 std::vector<int32_t> supportedProperties(
196 supportedPropConfigs.size());
197 for (const auto& config : supportedPropConfigs) {
198 supportedProperties.push_back(config.prop);
199 }
200 }
201
~VehicleHalManager()202 VehicleHalManager::~VehicleHalManager() {
203 mBatchingConsumer.requestStop();
204 mEventQueue.deactivate();
205 // We have to wait until consumer thread is fully stopped because it may
206 // be in a state of running callback (onBatchHalEvent).
207 mBatchingConsumer.waitStopped();
208 ALOGI("VehicleHalManager::dtor");
209 }
210
onHalEvent(VehiclePropValuePtr v)211 void VehicleHalManager::onHalEvent(VehiclePropValuePtr v) {
212 mEventQueue.push(std::move(v));
213 }
214
onHalPropertySetError(StatusCode errorCode,int32_t property,int32_t areaId)215 void VehicleHalManager::onHalPropertySetError(StatusCode errorCode,
216 int32_t property,
217 int32_t areaId) {
218 const auto& clients =
219 mSubscriptionManager.getSubscribedClients(property, SubscribeFlags::EVENTS_FROM_CAR);
220
221 for (const auto& client : clients) {
222 client->getCallback()->onPropertySetError(errorCode, property, areaId);
223 }
224 }
225
onBatchHalEvent(const std::vector<VehiclePropValuePtr> & values)226 void VehicleHalManager::onBatchHalEvent(const std::vector<VehiclePropValuePtr>& values) {
227 const auto& clientValues =
228 mSubscriptionManager.distributeValuesToClients(values, SubscribeFlags::EVENTS_FROM_CAR);
229
230 for (const HalClientValues& cv : clientValues) {
231 auto vecSize = cv.values.size();
232 hidl_vec<VehiclePropValue> vec;
233 if (vecSize < kMaxHidlVecOfVehiclPropValuePoolSize) {
234 vec.setToExternal(&mHidlVecOfVehiclePropValuePool[0], vecSize);
235 } else {
236 vec.resize(vecSize);
237 }
238
239 int i = 0;
240 for (VehiclePropValue* pValue : cv.values) {
241 shallowCopy(&(vec)[i++], *pValue);
242 }
243 auto status = cv.client->getCallback()->onPropertyEvent(vec);
244 if (!status.isOk()) {
245 ALOGE("Failed to notify client %s, err: %s",
246 toString(cv.client->getCallback()).c_str(),
247 status.description().c_str());
248 }
249 }
250 }
251
isSampleRateFixed(VehiclePropertyChangeMode mode)252 bool VehicleHalManager::isSampleRateFixed(VehiclePropertyChangeMode mode) {
253 return (mode & VehiclePropertyChangeMode::ON_CHANGE);
254 }
255
checkSampleRate(const VehiclePropConfig & config,float sampleRate)256 float VehicleHalManager::checkSampleRate(const VehiclePropConfig &config,
257 float sampleRate) {
258 if (isSampleRateFixed(config.changeMode)) {
259 if (std::abs(sampleRate) > std::numeric_limits<float>::epsilon()) {
260 ALOGW("Sample rate is greater than zero for on change type. "
261 "Ignoring it.");
262 }
263 return 0.0;
264 } else {
265 if (sampleRate > config.maxSampleRate) {
266 ALOGW("Sample rate %f is higher than max %f. Setting sampling rate "
267 "to max.", sampleRate, config.maxSampleRate);
268 return config.maxSampleRate;
269 }
270 if (sampleRate < config.minSampleRate) {
271 ALOGW("Sample rate %f is lower than min %f. Setting sampling rate "
272 "to min.", sampleRate, config.minSampleRate);
273 return config.minSampleRate;
274 }
275 }
276 return sampleRate; // Provided sample rate was good, no changes.
277 }
278
isSubscribable(const VehiclePropConfig & config,SubscribeFlags flags)279 bool VehicleHalManager::isSubscribable(const VehiclePropConfig& config,
280 SubscribeFlags flags) {
281 bool isReadable = config.access & VehiclePropertyAccess::READ;
282
283 if (!isReadable && (SubscribeFlags::EVENTS_FROM_CAR & flags)) {
284 ALOGW("Cannot subscribe, property 0x%x is not readable", config.prop);
285 return false;
286 }
287 if (config.changeMode == VehiclePropertyChangeMode::STATIC) {
288 ALOGW("Cannot subscribe, property 0x%x is static", config.prop);
289 return false;
290 }
291 return true;
292 }
293
checkWritePermission(const VehiclePropConfig & config) const294 bool VehicleHalManager::checkWritePermission(const VehiclePropConfig &config) const {
295 if (!(config.access & VehiclePropertyAccess::WRITE)) {
296 ALOGW("Property 0%x has no write access", config.prop);
297 return false;
298 } else {
299 return true;
300 }
301 }
302
checkReadPermission(const VehiclePropConfig & config) const303 bool VehicleHalManager::checkReadPermission(const VehiclePropConfig &config) const {
304 if (!(config.access & VehiclePropertyAccess::READ)) {
305 ALOGW("Property 0%x has no read access", config.prop);
306 return false;
307 } else {
308 return true;
309 }
310 }
311
handlePropertySetEvent(const VehiclePropValue & value)312 void VehicleHalManager::handlePropertySetEvent(const VehiclePropValue& value) {
313 auto clients =
314 mSubscriptionManager.getSubscribedClients(value.prop, SubscribeFlags::EVENTS_FROM_ANDROID);
315 for (const auto& client : clients) {
316 client->getCallback()->onPropertySet(value);
317 }
318 }
319
getPropConfigOrNull(int32_t prop) const320 const VehiclePropConfig* VehicleHalManager::getPropConfigOrNull(
321 int32_t prop) const {
322 return mConfigIndex->hasConfig(prop)
323 ? &mConfigIndex->getConfig(prop) : nullptr;
324 }
325
onAllClientsUnsubscribed(int32_t propertyId)326 void VehicleHalManager::onAllClientsUnsubscribed(int32_t propertyId) {
327 mHal->unsubscribe(propertyId);
328 }
329
getClientId(const sp<IVehicleCallback> & callback)330 ClientId VehicleHalManager::getClientId(const sp<IVehicleCallback>& callback) {
331 //TODO(b/32172906): rework this to get some kind of unique id for callback interface when this
332 // feature is ready in HIDL.
333
334 if (callback->isRemote()) {
335 BpHwVehicleCallback* hwCallback = static_cast<BpHwVehicleCallback*>(callback.get());
336 return static_cast<ClientId>(reinterpret_cast<intptr_t>(hwCallback->onAsBinder()));
337 } else {
338 return static_cast<ClientId>(reinterpret_cast<intptr_t>(callback.get()));
339 }
340 }
341
342 } // namespace V2_0
343 } // namespace vehicle
344 } // namespace automotive
345 } // namespace hardware
346 } // namespace android
347