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