blob: 73bb521ddbe082f778a9844885bcc6017d744fdd [file] [log] [blame]
Hao Chen6cb86892023-04-10 15:21:59 -07001/*
2 * Copyright (C) 2023 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 <GRPCVehicleHardware.h>
18
19#include "ProtoMessageConverter.h"
20
21#include <android-base/logging.h>
22#include <grpc++/grpc++.h>
Yu Shanabd92c12024-07-03 16:13:18 -070023#include <utils/SystemClock.h>
Hao Chen6cb86892023-04-10 15:21:59 -070024
25#include <cstdlib>
26#include <mutex>
27#include <shared_mutex>
28#include <utility>
29
30namespace android::hardware::automotive::vehicle::virtualization {
31
Yu Shanabd92c12024-07-03 16:13:18 -070032namespace {
33
34constexpr size_t MAX_RETRY_COUNT = 5;
35
36std::shared_ptr<::grpc::ChannelCredentials> getChannelCredentials() {
Hao Chen6cb86892023-04-10 15:21:59 -070037 return ::grpc::InsecureChannelCredentials();
38}
39
Yu Shanabd92c12024-07-03 16:13:18 -070040} // namespace
41
Hao Chen6cb86892023-04-10 15:21:59 -070042GRPCVehicleHardware::GRPCVehicleHardware(std::string service_addr)
43 : mServiceAddr(std::move(service_addr)),
44 mGrpcChannel(::grpc::CreateChannel(mServiceAddr, getChannelCredentials())),
45 mGrpcStub(proto::VehicleServer::NewStub(mGrpcChannel)),
46 mValuePollingThread([this] { ValuePollingLoop(); }) {}
47
Yu Shan5c846f72024-05-16 15:39:51 -070048// Only used for unit testing.
Yu Shanabd92c12024-07-03 16:13:18 -070049GRPCVehicleHardware::GRPCVehicleHardware(std::unique_ptr<proto::VehicleServer::StubInterface> stub,
50 bool startValuePollingLoop)
51 : mServiceAddr(""), mGrpcChannel(nullptr), mGrpcStub(std::move(stub)) {
52 if (startValuePollingLoop) {
53 mValuePollingThread = std::thread([this] { ValuePollingLoop(); });
54 }
55}
Yu Shan5c846f72024-05-16 15:39:51 -070056
Hao Chen6cb86892023-04-10 15:21:59 -070057GRPCVehicleHardware::~GRPCVehicleHardware() {
58 {
59 std::lock_guard lck(mShutdownMutex);
60 mShuttingDownFlag.store(true);
61 }
62 mShutdownCV.notify_all();
Yu Shanabd92c12024-07-03 16:13:18 -070063 if (mValuePollingThread.joinable()) {
64 mValuePollingThread.join();
65 }
Hao Chen6cb86892023-04-10 15:21:59 -070066}
67
68std::vector<aidlvhal::VehiclePropConfig> GRPCVehicleHardware::getAllPropertyConfigs() const {
69 std::vector<aidlvhal::VehiclePropConfig> configs;
70 ::grpc::ClientContext context;
71 auto config_stream = mGrpcStub->GetAllPropertyConfig(&context, ::google::protobuf::Empty());
72 proto::VehiclePropConfig protoConfig;
73 while (config_stream->Read(&protoConfig)) {
74 aidlvhal::VehiclePropConfig config;
75 proto_msg_converter::protoToAidl(protoConfig, &config);
76 configs.push_back(std::move(config));
77 }
78 auto grpc_status = config_stream->Finish();
79 if (!grpc_status.ok()) {
80 LOG(ERROR) << __func__
81 << ": GRPC GetAllPropertyConfig Failed: " << grpc_status.error_message();
82 }
83 return configs;
84}
85
86aidlvhal::StatusCode GRPCVehicleHardware::setValues(
87 std::shared_ptr<const SetValuesCallback> callback,
88 const std::vector<aidlvhal::SetValueRequest>& requests) {
89 ::grpc::ClientContext context;
90 proto::VehiclePropValueRequests protoRequests;
91 proto::SetValueResults protoResults;
92 for (const auto& request : requests) {
93 auto& protoRequest = *protoRequests.add_requests();
94 protoRequest.set_request_id(request.requestId);
95 proto_msg_converter::aidlToProto(request.value, protoRequest.mutable_value());
96 }
97 // TODO(chenhaosjtuacm): Make it Async.
98 auto grpc_status = mGrpcStub->SetValues(&context, protoRequests, &protoResults);
99 if (!grpc_status.ok()) {
100 LOG(ERROR) << __func__ << ": GRPC SetValues Failed: " << grpc_status.error_message();
101 {
102 std::shared_lock lck(mCallbackMutex);
103 // TODO(chenhaosjtuacm): call on-set-error callback.
104 }
105 return aidlvhal::StatusCode::INTERNAL_ERROR;
106 }
107 std::vector<aidlvhal::SetValueResult> results;
108 for (const auto& protoResult : protoResults.results()) {
109 auto& result = results.emplace_back();
110 result.requestId = protoResult.request_id();
111 result.status = static_cast<aidlvhal::StatusCode>(protoResult.status());
112 // TODO(chenhaosjtuacm): call on-set-error callback.
113 }
114 (*callback)(std::move(results));
115
116 return aidlvhal::StatusCode::OK;
117}
118
119aidlvhal::StatusCode GRPCVehicleHardware::getValues(
120 std::shared_ptr<const GetValuesCallback> callback,
121 const std::vector<aidlvhal::GetValueRequest>& requests) const {
Yu Shanabd92c12024-07-03 16:13:18 -0700122 std::vector<aidlvhal::GetValueResult> results;
123 auto status = getValuesWithRetry(requests, &results, /*retryCount=*/0);
124 if (status != aidlvhal::StatusCode::OK) {
125 return status;
126 }
127 if (!results.empty()) {
128 (*callback)(std::move(results));
129 }
130 return status;
131}
132
133aidlvhal::StatusCode GRPCVehicleHardware::getValuesWithRetry(
134 const std::vector<aidlvhal::GetValueRequest>& requests,
135 std::vector<aidlvhal::GetValueResult>* results, size_t retryCount) const {
136 if (retryCount == MAX_RETRY_COUNT) {
137 LOG(ERROR) << __func__ << ": GRPC GetValues Failed, failed to get the latest value after "
138 << retryCount << " retries";
139 return aidlvhal::StatusCode::TRY_AGAIN;
140 }
141
Hao Chen6cb86892023-04-10 15:21:59 -0700142 proto::VehiclePropValueRequests protoRequests;
Yu Shanabd92c12024-07-03 16:13:18 -0700143 std::unordered_map<int64_t, const aidlvhal::GetValueRequest*> requestById;
Hao Chen6cb86892023-04-10 15:21:59 -0700144 for (const auto& request : requests) {
145 auto& protoRequest = *protoRequests.add_requests();
146 protoRequest.set_request_id(request.requestId);
147 proto_msg_converter::aidlToProto(request.prop, protoRequest.mutable_value());
Yu Shanabd92c12024-07-03 16:13:18 -0700148 requestById[request.requestId] = &request;
Hao Chen6cb86892023-04-10 15:21:59 -0700149 }
Yu Shanabd92c12024-07-03 16:13:18 -0700150
Hao Chen6cb86892023-04-10 15:21:59 -0700151 // TODO(chenhaosjtuacm): Make it Async.
Yu Shanabd92c12024-07-03 16:13:18 -0700152 ::grpc::ClientContext context;
153 proto::GetValueResults protoResults;
Hao Chen6cb86892023-04-10 15:21:59 -0700154 auto grpc_status = mGrpcStub->GetValues(&context, protoRequests, &protoResults);
155 if (!grpc_status.ok()) {
156 LOG(ERROR) << __func__ << ": GRPC GetValues Failed: " << grpc_status.error_message();
157 return aidlvhal::StatusCode::INTERNAL_ERROR;
158 }
Yu Shanabd92c12024-07-03 16:13:18 -0700159
160 std::vector<aidlvhal::GetValueRequest> retryRequests;
Hao Chen6cb86892023-04-10 15:21:59 -0700161 for (const auto& protoResult : protoResults.results()) {
Yu Shanabd92c12024-07-03 16:13:18 -0700162 int64_t requestId = protoResult.request_id();
163 auto it = requestById.find(requestId);
164 if (it == requestById.end()) {
165 LOG(ERROR) << __func__
166 << "Invalid getValue request with unknown request ID: " << requestId
167 << ", ignore";
168 continue;
Hao Chen6cb86892023-04-10 15:21:59 -0700169 }
Yu Shanabd92c12024-07-03 16:13:18 -0700170
171 if (!protoResult.has_value()) {
172 auto& result = results->emplace_back();
173 result.requestId = requestId;
174 result.status = static_cast<aidlvhal::StatusCode>(protoResult.status());
175 continue;
176 }
177
178 aidlvhal::VehiclePropValue value;
179 proto_msg_converter::protoToAidl(protoResult.value(), &value);
180
181 // VHAL proxy server uses a different timestamp then AAOS timestamp, so we have to reset
182 // the timestamp.
183 // TODO(b/350822044): Remove this once we use timestamp from proxy server.
184 if (!setAndroidTimestamp(&value)) {
185 // This is a rare case when we receive a property update event reflecting a new value
186 // for the property before we receive the get value result. This means that the result
187 // is already outdated, hence we should retry getting the latest value again.
188 LOG(WARNING) << __func__ << "getValue result for propId: " << value.prop
189 << " areaId: " << value.areaId << " is oudated, retry";
190 retryRequests.push_back(*(it->second));
191 continue;
192 }
193
194 auto& result = results->emplace_back();
195 result.requestId = requestId;
196 result.status = static_cast<aidlvhal::StatusCode>(protoResult.status());
197 result.prop = std::move(value);
Hao Chen6cb86892023-04-10 15:21:59 -0700198 }
Yu Shanabd92c12024-07-03 16:13:18 -0700199
200 if (retryRequests.size() != 0) {
201 return getValuesWithRetry(retryRequests, results, retryCount++);
202 }
Hao Chen6cb86892023-04-10 15:21:59 -0700203
204 return aidlvhal::StatusCode::OK;
205}
206
Yu Shanabd92c12024-07-03 16:13:18 -0700207bool GRPCVehicleHardware::setAndroidTimestamp(aidlvhal::VehiclePropValue* propValue) const {
208 PropIdAreaId propIdAreaId = {
209 .propId = propValue->prop,
210 .areaId = propValue->areaId,
211 };
212 int64_t now = elapsedRealtimeNano();
213 int64_t externalTimestamp = propValue->timestamp;
214
215 {
216 std::lock_guard lck(mLatestUpdateTimestampsMutex);
217 auto it = mLatestUpdateTimestamps.find(propIdAreaId);
218 if (it == mLatestUpdateTimestamps.end() || externalTimestamp > (it->second).first) {
219 mLatestUpdateTimestamps[propIdAreaId].first = externalTimestamp;
220 mLatestUpdateTimestamps[propIdAreaId].second = now;
221 propValue->timestamp = now;
222 return true;
223 }
224 if (externalTimestamp == (it->second).first) {
225 propValue->timestamp = (it->second).second;
226 return true;
227 }
228 }
229 // externalTimestamp < (it->second).first, the value is outdated.
230 return false;
231}
232
Hao Chen6cb86892023-04-10 15:21:59 -0700233void GRPCVehicleHardware::registerOnPropertyChangeEvent(
234 std::unique_ptr<const PropertyChangeCallback> callback) {
235 std::lock_guard lck(mCallbackMutex);
236 if (mOnPropChange) {
237 LOG(ERROR) << __func__ << " must only be called once.";
238 return;
239 }
240 mOnPropChange = std::move(callback);
241}
242
243void GRPCVehicleHardware::registerOnPropertySetErrorEvent(
244 std::unique_ptr<const PropertySetErrorCallback> callback) {
245 std::lock_guard lck(mCallbackMutex);
246 if (mOnSetErr) {
247 LOG(ERROR) << __func__ << " must only be called once.";
248 return;
249 }
250 mOnSetErr = std::move(callback);
251}
252
Hao Chena810fb22023-04-11 15:27:44 -0700253DumpResult GRPCVehicleHardware::dump(const std::vector<std::string>& options) {
254 ::grpc::ClientContext context;
255 proto::DumpOptions protoDumpOptions;
256 proto::DumpResult protoDumpResult;
257 for (const auto& option : options) {
258 protoDumpOptions.add_options(option);
259 }
260 auto grpc_status = mGrpcStub->Dump(&context, protoDumpOptions, &protoDumpResult);
261 if (!grpc_status.ok()) {
262 LOG(ERROR) << __func__ << ": GRPC Dump Failed: " << grpc_status.error_message();
263 return {};
264 }
265 return {
266 .callerShouldDumpState = protoDumpResult.caller_should_dump_state(),
267 .buffer = protoDumpResult.buffer(),
268 };
Hao Chen6cb86892023-04-10 15:21:59 -0700269}
270
271aidlvhal::StatusCode GRPCVehicleHardware::checkHealth() {
Hao Chena810fb22023-04-11 15:27:44 -0700272 ::grpc::ClientContext context;
273 proto::VehicleHalCallStatus protoStatus;
274 auto grpc_status = mGrpcStub->CheckHealth(&context, ::google::protobuf::Empty(), &protoStatus);
275 if (!grpc_status.ok()) {
276 LOG(ERROR) << __func__ << ": GRPC CheckHealth Failed: " << grpc_status.error_message();
277 return aidlvhal::StatusCode::INTERNAL_ERROR;
278 }
279 return static_cast<aidlvhal::StatusCode>(protoStatus.status_code());
Hao Chen6cb86892023-04-10 15:21:59 -0700280}
281
Yu Shan5c846f72024-05-16 15:39:51 -0700282aidlvhal::StatusCode GRPCVehicleHardware::subscribe(aidlvhal::SubscribeOptions options) {
283 proto::SubscribeRequest request;
284 ::grpc::ClientContext context;
285 proto::VehicleHalCallStatus protoStatus;
286 proto_msg_converter::aidlToProto(options, request.mutable_options());
287 auto grpc_status = mGrpcStub->Subscribe(&context, request, &protoStatus);
288 if (!grpc_status.ok()) {
289 if (grpc_status.error_code() == ::grpc::StatusCode::UNIMPLEMENTED) {
290 // This is a legacy sever. It should handle updateSampleRate.
291 LOG(INFO) << __func__ << ": GRPC Subscribe is not supported by the server";
292 return aidlvhal::StatusCode::OK;
293 }
294 LOG(ERROR) << __func__ << ": GRPC Subscribe Failed: " << grpc_status.error_message();
295 return aidlvhal::StatusCode::INTERNAL_ERROR;
296 }
297 return static_cast<aidlvhal::StatusCode>(protoStatus.status_code());
298}
299
Yu Shan2c37c112024-05-20 17:27:19 -0700300aidlvhal::StatusCode GRPCVehicleHardware::unsubscribe(int32_t propId, int32_t areaId) {
301 proto::UnsubscribeRequest request;
302 ::grpc::ClientContext context;
303 proto::VehicleHalCallStatus protoStatus;
304 request.set_prop_id(propId);
305 request.set_area_id(areaId);
306 auto grpc_status = mGrpcStub->Unsubscribe(&context, request, &protoStatus);
307 if (!grpc_status.ok()) {
308 if (grpc_status.error_code() == ::grpc::StatusCode::UNIMPLEMENTED) {
309 // This is a legacy sever. Ignore unsubscribe request.
310 LOG(INFO) << __func__ << ": GRPC Unsubscribe is not supported by the server";
311 return aidlvhal::StatusCode::OK;
312 }
313 LOG(ERROR) << __func__ << ": GRPC Unsubscribe Failed: " << grpc_status.error_message();
314 return aidlvhal::StatusCode::INTERNAL_ERROR;
315 }
316 return static_cast<aidlvhal::StatusCode>(protoStatus.status_code());
317}
318
Hao Chena810fb22023-04-11 15:27:44 -0700319aidlvhal::StatusCode GRPCVehicleHardware::updateSampleRate(int32_t propId, int32_t areaId,
320 float sampleRate) {
321 ::grpc::ClientContext context;
322 proto::UpdateSampleRateRequest request;
323 proto::VehicleHalCallStatus protoStatus;
324 request.set_prop(propId);
325 request.set_area_id(areaId);
326 request.set_sample_rate(sampleRate);
327 auto grpc_status = mGrpcStub->UpdateSampleRate(&context, request, &protoStatus);
328 if (!grpc_status.ok()) {
329 LOG(ERROR) << __func__ << ": GRPC UpdateSampleRate Failed: " << grpc_status.error_message();
330 return aidlvhal::StatusCode::INTERNAL_ERROR;
331 }
332 return static_cast<aidlvhal::StatusCode>(protoStatus.status_code());
Hao Chen6cb86892023-04-10 15:21:59 -0700333}
334
335bool GRPCVehicleHardware::waitForConnected(std::chrono::milliseconds waitTime) {
336 return mGrpcChannel->WaitForConnected(gpr_time_add(
337 gpr_now(GPR_CLOCK_MONOTONIC), gpr_time_from_millis(waitTime.count(), GPR_TIMESPAN)));
338}
339
340void GRPCVehicleHardware::ValuePollingLoop() {
341 while (!mShuttingDownFlag.load()) {
Yu Shanabd92c12024-07-03 16:13:18 -0700342 pollValue();
Hao Chen6cb86892023-04-10 15:21:59 -0700343 // try to reconnect
344 }
345}
346
Yu Shanabd92c12024-07-03 16:13:18 -0700347void GRPCVehicleHardware::pollValue() {
348 ::grpc::ClientContext context;
349
350 bool rpc_stopped{false};
351 std::thread shuttingdown_watcher([this, &rpc_stopped, &context]() {
352 std::unique_lock<std::mutex> lck(mShutdownMutex);
353 mShutdownCV.wait(
354 lck, [this, &rpc_stopped]() { return rpc_stopped || mShuttingDownFlag.load(); });
355 context.TryCancel();
356 });
357
358 auto value_stream = mGrpcStub->StartPropertyValuesStream(&context, ::google::protobuf::Empty());
359 LOG(INFO) << __func__ << ": GRPC Value Streaming Started";
360 proto::VehiclePropValues protoValues;
361 while (!mShuttingDownFlag.load() && value_stream->Read(&protoValues)) {
362 std::vector<aidlvhal::VehiclePropValue> values;
363 for (const auto protoValue : protoValues.values()) {
364 aidlvhal::VehiclePropValue aidlValue = {};
365 proto_msg_converter::protoToAidl(protoValue, &aidlValue);
366
367 // VHAL proxy server uses a different timestamp then AAOS timestamp, so we have to
368 // reset the timestamp.
369 // TODO(b/350822044): Remove this once we use timestamp from proxy server.
370 if (!setAndroidTimestamp(&aidlValue)) {
371 LOG(WARNING) << __func__ << ": property event for propId: " << aidlValue.prop
372 << " areaId: " << aidlValue.areaId << " is outdated, ignore";
373 continue;
374 }
375
376 values.push_back(std::move(aidlValue));
377 }
378 if (values.empty()) {
379 continue;
380 }
381 std::shared_lock lck(mCallbackMutex);
382 if (mOnPropChange) {
383 (*mOnPropChange)(values);
384 }
385 }
386
387 {
388 std::lock_guard lck(mShutdownMutex);
389 rpc_stopped = true;
390 }
391 mShutdownCV.notify_all();
392 shuttingdown_watcher.join();
393
394 auto grpc_status = value_stream->Finish();
395 // never reach here until connection lost
396 LOG(ERROR) << __func__ << ": GRPC Value Streaming Failed: " << grpc_status.error_message();
397}
398
Hao Chen6cb86892023-04-10 15:21:59 -0700399} // namespace android::hardware::automotive::vehicle::virtualization