• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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