1 /*
2 * Copyright 2020 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 #include "VhalHandler.h"
18
19 #include <chrono>
20 #include <cmath>
21 #include <condition_variable>
22 #include <mutex>
23
24 #include <android-base/logging.h>
25 #include <android/hardware/automotive/vehicle/2.0/IVehicle.h>
26 #include <time.h>
27 #include <utils/SystemClock.h>
28 #include <utils/Timers.h>
29
30 namespace android {
31 namespace hardware {
32 namespace automotive {
33 namespace sv {
34 namespace V1_0 {
35 namespace implementation {
36
37 using vehicle::V2_0::IVehicle;
38 using vehicle::V2_0::StatusCode;
39 using vehicle::V2_0::VehiclePropertyType;
40 using vehicle::V2_0::VehiclePropValue;
41
initialize(UpdateMethod updateMethod,int rate)42 bool VhalHandler::initialize(UpdateMethod updateMethod, int rate) {
43 LOG(DEBUG) << __FUNCTION__;
44 std::scoped_lock<std::mutex> lock(mAccessLock);
45
46 if (mIsInitialized) {
47 LOG(ERROR) << "Vehicle Handler is already initialized.";
48 return false;
49 }
50
51 LOG(INFO) << "Connecting to Vehicle HAL";
52 mVhalServicePtr = IVehicle::getService();
53 if (mVhalServicePtr.get() == nullptr) {
54 LOG(ERROR) << "Vehicle HAL getService failed.";
55 return false;
56 }
57
58 if (rate < 1 || rate > 100) {
59 LOG(ERROR) << "Rate must be in the range [1, 100].";
60 return false;
61 }
62
63 if (mUpdateMethod == UpdateMethod::SUBSCRIBE) {
64 LOG(ERROR) << "Update method Subscribe is not currently implemented.";
65 return false;
66 }
67
68 mUpdateMethod = updateMethod;
69 mRate = rate;
70 mIsInitialized = true;
71 mIsUpdateActive = false;
72
73 return true;
74 }
75
pollProperties()76 void VhalHandler::pollProperties() {
77 LOG(DEBUG) << "Polling thread started.";
78 while (true) {
79 nsecs_t startTime = elapsedRealtimeNano();
80
81 // Copy properties to read.
82 std::vector<VehiclePropValue> propertiesToRead;
83 int rate;
84 {
85 std::scoped_lock<std::mutex> lock(mAccessLock);
86 if (!mIsUpdateActive) {
87 LOG(DEBUG) << "Exiting polling thread.";
88 break;
89 }
90 propertiesToRead = mPropertiesToRead;
91 rate = mRate;
92 }
93
94 // Make get call for each VHAL property.
95 // Write to back property values, note lock is not needed as only this thread uses it.
96 std::vector<VehiclePropValue> vehiclePropValuesUpdated;
97 for (auto& propertyToRead : propertiesToRead) {
98 StatusCode statusResult;
99 VehiclePropValue propValueResult;
100 mVhalServicePtr->get(propertyToRead,
101 [&statusResult,
102 &propValueResult](StatusCode status,
103 const VehiclePropValue& propValue) {
104 statusResult = status;
105 propValueResult = propValue;
106 });
107 if (statusResult != StatusCode::OK) {
108 LOG(WARNING) << "Failed to read vhal property: " << propertyToRead.prop
109 << ", with status code: " << static_cast<int32_t>(statusResult);
110 } else {
111 vehiclePropValuesUpdated.push_back(propValueResult);
112 }
113 }
114
115 // Update property values by swapping with updated property values.
116 {
117 std::scoped_lock<std::mutex> lock(mAccessLock);
118 std::swap(mPropertyValues, vehiclePropValuesUpdated);
119 }
120
121 std::unique_lock<std::mutex> sleepLock(mPollThreadSleepMutex);
122 // Sleep to generate frames at kTargetFrameRate.
123 // rate is number of updates per seconds,
124 // Target time period between two updates in nano-seconds = (10 ^ 9) / rate.
125 const nsecs_t kTargetRateNs = std::pow(10, 9) / mRate;
126 const nsecs_t now = elapsedRealtimeNano();
127 const nsecs_t workTimeNs = now - startTime;
128 const nsecs_t sleepDurationNs = kTargetRateNs - workTimeNs;
129 if (sleepDurationNs > 0) {
130 // Sleep for sleepDurationNs or until a stop signal is received.
131 mPollThreadCondition.wait_for(sleepLock, std::chrono::nanoseconds(sleepDurationNs),
132 [this]() { return mPollStopSleeping; });
133 }
134 }
135 }
136
startPropertiesUpdate()137 bool VhalHandler::startPropertiesUpdate() {
138 LOG(DEBUG) << __FUNCTION__;
139 std::scoped_lock<std::mutex> lock(mAccessLock);
140
141 // Check Vhal service is initialized.
142 if (!mIsInitialized) {
143 LOG(ERROR) << "VHAL handler not initialized.";
144 return false;
145 }
146
147 if (mIsUpdateActive) {
148 LOG(ERROR) << "Polling is already started.";
149 return false;
150 }
151
152 mIsUpdateActive = true;
153
154 {
155 std::scoped_lock<std::mutex> sleepLock(mPollThreadSleepMutex);
156 mPollStopSleeping = false;
157 }
158
159 // Start polling thread if updated method is GET.
160 if (mUpdateMethod == UpdateMethod::GET) {
161 mPollingThread = std::thread([this]() { pollProperties(); });
162 }
163
164 return true;
165 }
166
setPropertiesToRead(const std::vector<VehiclePropValue> & propertiesToRead)167 bool VhalHandler::setPropertiesToRead(const std::vector<VehiclePropValue>& propertiesToRead) {
168 LOG(DEBUG) << __FUNCTION__;
169 std::scoped_lock<std::mutex> lock(mAccessLock);
170
171 // Replace property ids to read.
172 mPropertiesToRead = propertiesToRead;
173
174 return true;
175 }
176
setPropertiesToRead(const std::vector<uint64_t> & propertiesToRead)177 bool VhalHandler::setPropertiesToRead(const std::vector<uint64_t>& propertiesToRead) {
178 LOG(DEBUG) << __FUNCTION__;
179 std::vector<VehiclePropValue> vhalPropValues;
180 for (const auto& property : propertiesToRead) {
181 VehiclePropValue propValue;
182 // Higher 32 bits = property id, lower 32 bits = area id.
183 propValue.areaId = property & 0xFFFFFFFF;
184 propValue.prop = (property >> 32) & 0xFFFFFFFF;
185 vhalPropValues.push_back(propValue);
186 }
187 return setPropertiesToRead(vhalPropValues);
188 }
189
getPropertyValues(std::vector<VehiclePropValue> * property_values)190 bool VhalHandler::getPropertyValues(std::vector<VehiclePropValue>* property_values) {
191 LOG(DEBUG) << __FUNCTION__;
192 std::scoped_lock<std::mutex> lock(mAccessLock);
193
194 // Check Vhal service is initialized.
195 if (!mIsInitialized) {
196 LOG(ERROR) << "VHAL handler not initialized.";
197 return false;
198 }
199
200 // Copy current property values to argument.
201 *property_values = mPropertyValues;
202
203 return true;
204 }
205
stopPropertiesUpdate()206 bool VhalHandler::stopPropertiesUpdate() {
207 LOG(DEBUG) << __FUNCTION__;
208 {
209 std::scoped_lock<std::mutex> lock(mAccessLock);
210
211 // Check Vhal service is initialized.
212 if (!mIsInitialized) {
213 LOG(ERROR) << "VHAL handler not initialized.";
214 return false;
215 }
216
217 if (!mIsUpdateActive) {
218 LOG(ERROR) << "Polling is already stopped.";
219 return false;
220 }
221
222 mIsUpdateActive = false;
223 }
224
225 // Wake up the polling thread.
226 {
227 std::scoped_lock<std::mutex> sleepLock(mPollThreadSleepMutex);
228 mPollStopSleeping = true;
229 }
230 mPollThreadCondition.notify_one();
231
232 // Wait for polling thread to exit.
233 mPollingThread.join();
234
235 return true;
236 }
237
238 } // namespace implementation
239 } // namespace V1_0
240 } // namespace sv
241 } // namespace automotive
242 } // namespace hardware
243 } // namespace android
244