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 int32_t areas = isGlobalProp(prop) ? 0 : ops.vehicleAreas;
146 if (areas != 0 && ((areas & config->supportedAreas) != areas)) {
147 ALOGE("Failed to subscribe property 0x%x. Requested areas 0x%x are "
148 "out of supported range of 0x%x", prop, ops.vehicleAreas,
149 config->supportedAreas);
150 return StatusCode::INVALID_ARG;
151 }
152
153 ops.vehicleAreas = areas;
154 ops.sampleRate = checkSampleRate(*config, ops.sampleRate);
155 }
156
157 std::list<SubscribeOptions> updatedOptions;
158 auto res = mSubscriptionManager.addOrUpdateSubscription(getClientId(callback),
159 callback, verifiedOptions,
160 &updatedOptions);
161 if (StatusCode::OK != res) {
162 ALOGW("%s failed to subscribe, error code: %d", __func__, res);
163 return res;
164 }
165
166 for (auto opt : updatedOptions) {
167 mHal->subscribe(opt.propId, opt.vehicleAreas, opt.sampleRate);
168 }
169
170 return StatusCode::OK;
171 }
172
unsubscribe(const sp<IVehicleCallback> & callback,int32_t propId)173 Return<StatusCode> VehicleHalManager::unsubscribe(const sp<IVehicleCallback>& callback,
174 int32_t propId) {
175 mSubscriptionManager.unsubscribe(getClientId(callback), propId);
176 return StatusCode::OK;
177 }
178
debugDump(IVehicle::debugDump_cb _hidl_cb)179 Return<void> VehicleHalManager::debugDump(IVehicle::debugDump_cb _hidl_cb) {
180 _hidl_cb("");
181 return Void();
182 }
183
init()184 void VehicleHalManager::init() {
185 ALOGI("VehicleHalManager::init");
186
187 mHidlVecOfVehiclePropValuePool.resize(kMaxHidlVecOfVehiclPropValuePoolSize);
188
189
190 mBatchingConsumer.run(&mEventQueue,
191 kHalEventBatchingTimeWindow,
192 std::bind(&VehicleHalManager::onBatchHalEvent,
193 this, _1));
194
195 mHal->init(&mValueObjectPool,
196 std::bind(&VehicleHalManager::onHalEvent, this, _1),
197 std::bind(&VehicleHalManager::onHalPropertySetError, this,
198 _1, _2, _3));
199
200 // Initialize index with vehicle configurations received from VehicleHal.
201 auto supportedPropConfigs = mHal->listProperties();
202 mConfigIndex.reset(new VehiclePropConfigIndex(supportedPropConfigs));
203
204 std::vector<int32_t> supportedProperties(
205 supportedPropConfigs.size());
206 for (const auto& config : supportedPropConfigs) {
207 supportedProperties.push_back(config.prop);
208 }
209 }
210
~VehicleHalManager()211 VehicleHalManager::~VehicleHalManager() {
212 mBatchingConsumer.requestStop();
213 mEventQueue.deactivate();
214 // We have to wait until consumer thread is fully stopped because it may
215 // be in a state of running callback (onBatchHalEvent).
216 mBatchingConsumer.waitStopped();
217 ALOGI("VehicleHalManager::dtor");
218 }
219
onHalEvent(VehiclePropValuePtr v)220 void VehicleHalManager::onHalEvent(VehiclePropValuePtr v) {
221 mEventQueue.push(std::move(v));
222 }
223
onHalPropertySetError(StatusCode errorCode,int32_t property,int32_t areaId)224 void VehicleHalManager::onHalPropertySetError(StatusCode errorCode,
225 int32_t property,
226 int32_t areaId) {
227 const auto& clients = mSubscriptionManager.getSubscribedClients(
228 property, 0, SubscribeFlags::HAL_EVENT);
229
230 for (auto client : clients) {
231 client->getCallback()->onPropertySetError(errorCode, property, areaId);
232 }
233 }
234
onBatchHalEvent(const std::vector<VehiclePropValuePtr> & values)235 void VehicleHalManager::onBatchHalEvent(const std::vector<VehiclePropValuePtr>& values) {
236 const auto& clientValues = mSubscriptionManager.distributeValuesToClients(
237 values, SubscribeFlags::HAL_EVENT);
238
239 for (const HalClientValues& cv : clientValues) {
240 auto vecSize = cv.values.size();
241 hidl_vec<VehiclePropValue> vec;
242 if (vecSize < kMaxHidlVecOfVehiclPropValuePoolSize) {
243 vec.setToExternal(&mHidlVecOfVehiclePropValuePool[0], vecSize);
244 } else {
245 vec.resize(vecSize);
246 }
247
248 int i = 0;
249 for (VehiclePropValue* pValue : cv.values) {
250 shallowCopy(&(vec)[i++], *pValue);
251 }
252 auto status = cv.client->getCallback()->onPropertyEvent(vec);
253 if (!status.isOk()) {
254 ALOGE("Failed to notify client %s, err: %s",
255 toString(cv.client->getCallback()).c_str(),
256 status.description().c_str());
257 }
258 }
259 }
260
isSampleRateFixed(VehiclePropertyChangeMode mode)261 bool VehicleHalManager::isSampleRateFixed(VehiclePropertyChangeMode mode) {
262 return (mode & VehiclePropertyChangeMode::ON_SET)
263 || (mode & VehiclePropertyChangeMode::ON_CHANGE);
264 }
265
checkSampleRate(const VehiclePropConfig & config,float sampleRate)266 float VehicleHalManager::checkSampleRate(const VehiclePropConfig &config,
267 float sampleRate) {
268 if (isSampleRateFixed(config.changeMode)) {
269 if (std::abs(sampleRate) > std::numeric_limits<float>::epsilon()) {
270 ALOGW("Sample rate is greater than zero for on change type. "
271 "Ignoring it.");
272 }
273 return 0.0;
274 } else {
275 if (sampleRate > config.maxSampleRate) {
276 ALOGW("Sample rate %f is higher than max %f. Setting sampling rate "
277 "to max.", sampleRate, config.maxSampleRate);
278 return config.maxSampleRate;
279 }
280 if (sampleRate < config.minSampleRate) {
281 ALOGW("Sample rate %f is lower than min %f. Setting sampling rate "
282 "to min.", sampleRate, config.minSampleRate);
283 return config.minSampleRate;
284 }
285 }
286 return sampleRate; // Provided sample rate was good, no changes.
287 }
288
isSubscribable(const VehiclePropConfig & config,SubscribeFlags flags)289 bool VehicleHalManager::isSubscribable(const VehiclePropConfig& config,
290 SubscribeFlags flags) {
291 bool isReadable = config.access & VehiclePropertyAccess::READ;
292
293 if (!isReadable && (SubscribeFlags::HAL_EVENT & flags)) {
294 ALOGW("Cannot subscribe, property 0x%x is not readable", config.prop);
295 return false;
296 }
297 if (config.changeMode == VehiclePropertyChangeMode::STATIC) {
298 ALOGW("Cannot subscribe, property 0x%x is static", config.prop);
299 return false;
300 }
301
302 //TODO: extend to support event notification for set from android
303 if (config.changeMode == VehiclePropertyChangeMode::POLL) {
304 ALOGW("Cannot subscribe, property 0x%x is poll only", config.prop);
305 return false;
306 }
307 return true;
308 }
309
checkWritePermission(const VehiclePropConfig & config) const310 bool VehicleHalManager::checkWritePermission(const VehiclePropConfig &config) const {
311 if (!(config.access & VehiclePropertyAccess::WRITE)) {
312 ALOGW("Property 0%x has no write access", config.prop);
313 return false;
314 } else {
315 return true;
316 }
317 }
318
checkReadPermission(const VehiclePropConfig & config) const319 bool VehicleHalManager::checkReadPermission(const VehiclePropConfig &config) const {
320 if (!(config.access & VehiclePropertyAccess::READ)) {
321 ALOGW("Property 0%x has no read access", config.prop);
322 return false;
323 } else {
324 return true;
325 }
326 }
327
handlePropertySetEvent(const VehiclePropValue & value)328 void VehicleHalManager::handlePropertySetEvent(const VehiclePropValue& value) {
329 auto clients = mSubscriptionManager.getSubscribedClients(
330 value.prop, value.areaId, SubscribeFlags::SET_CALL);
331 for (auto client : clients) {
332 client->getCallback()->onPropertySet(value);
333 }
334 }
335
getPropConfigOrNull(int32_t prop) const336 const VehiclePropConfig* VehicleHalManager::getPropConfigOrNull(
337 int32_t prop) const {
338 return mConfigIndex->hasConfig(prop)
339 ? &mConfigIndex->getConfig(prop) : nullptr;
340 }
341
onAllClientsUnsubscribed(int32_t propertyId)342 void VehicleHalManager::onAllClientsUnsubscribed(int32_t propertyId) {
343 mHal->unsubscribe(propertyId);
344 }
345
getClientId(const sp<IVehicleCallback> & callback)346 ClientId VehicleHalManager::getClientId(const sp<IVehicleCallback>& callback) {
347 //TODO(b/32172906): rework this to get some kind of unique id for callback interface when this
348 // feature is ready in HIDL.
349
350 if (callback->isRemote()) {
351 BpHwVehicleCallback* hwCallback = static_cast<BpHwVehicleCallback*>(callback.get());
352 return static_cast<ClientId>(reinterpret_cast<intptr_t>(hwCallback->onAsBinder()));
353 } else {
354 return static_cast<ClientId>(reinterpret_cast<intptr_t>(callback.get()));
355 }
356 }
357
358 } // namespace V2_0
359 } // namespace vehicle
360 } // namespace automotive
361 } // namespace hardware
362 } // namespace android
363