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