blob: 07422835d24cd4c03202f5b64b9e31323df16dd8 [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>
23
24#include <cstdlib>
25#include <mutex>
26#include <shared_mutex>
27#include <utility>
28
29namespace android::hardware::automotive::vehicle::virtualization {
30
31static std::shared_ptr<::grpc::ChannelCredentials> getChannelCredentials() {
32 // TODO(chenhaosjtuacm): get secured credentials here
33 return ::grpc::InsecureChannelCredentials();
34}
35
36GRPCVehicleHardware::GRPCVehicleHardware(std::string service_addr)
37 : mServiceAddr(std::move(service_addr)),
38 mGrpcChannel(::grpc::CreateChannel(mServiceAddr, getChannelCredentials())),
39 mGrpcStub(proto::VehicleServer::NewStub(mGrpcChannel)),
40 mValuePollingThread([this] { ValuePollingLoop(); }) {}
41
42GRPCVehicleHardware::~GRPCVehicleHardware() {
43 {
44 std::lock_guard lck(mShutdownMutex);
45 mShuttingDownFlag.store(true);
46 }
47 mShutdownCV.notify_all();
48 mValuePollingThread.join();
49}
50
51std::vector<aidlvhal::VehiclePropConfig> GRPCVehicleHardware::getAllPropertyConfigs() const {
52 std::vector<aidlvhal::VehiclePropConfig> configs;
53 ::grpc::ClientContext context;
54 auto config_stream = mGrpcStub->GetAllPropertyConfig(&context, ::google::protobuf::Empty());
55 proto::VehiclePropConfig protoConfig;
56 while (config_stream->Read(&protoConfig)) {
57 aidlvhal::VehiclePropConfig config;
58 proto_msg_converter::protoToAidl(protoConfig, &config);
59 configs.push_back(std::move(config));
60 }
61 auto grpc_status = config_stream->Finish();
62 if (!grpc_status.ok()) {
63 LOG(ERROR) << __func__
64 << ": GRPC GetAllPropertyConfig Failed: " << grpc_status.error_message();
65 }
66 return configs;
67}
68
69aidlvhal::StatusCode GRPCVehicleHardware::setValues(
70 std::shared_ptr<const SetValuesCallback> callback,
71 const std::vector<aidlvhal::SetValueRequest>& requests) {
72 ::grpc::ClientContext context;
73 proto::VehiclePropValueRequests protoRequests;
74 proto::SetValueResults protoResults;
75 for (const auto& request : requests) {
76 auto& protoRequest = *protoRequests.add_requests();
77 protoRequest.set_request_id(request.requestId);
78 proto_msg_converter::aidlToProto(request.value, protoRequest.mutable_value());
79 }
80 // TODO(chenhaosjtuacm): Make it Async.
81 auto grpc_status = mGrpcStub->SetValues(&context, protoRequests, &protoResults);
82 if (!grpc_status.ok()) {
83 LOG(ERROR) << __func__ << ": GRPC SetValues Failed: " << grpc_status.error_message();
84 {
85 std::shared_lock lck(mCallbackMutex);
86 // TODO(chenhaosjtuacm): call on-set-error callback.
87 }
88 return aidlvhal::StatusCode::INTERNAL_ERROR;
89 }
90 std::vector<aidlvhal::SetValueResult> results;
91 for (const auto& protoResult : protoResults.results()) {
92 auto& result = results.emplace_back();
93 result.requestId = protoResult.request_id();
94 result.status = static_cast<aidlvhal::StatusCode>(protoResult.status());
95 // TODO(chenhaosjtuacm): call on-set-error callback.
96 }
97 (*callback)(std::move(results));
98
99 return aidlvhal::StatusCode::OK;
100}
101
102aidlvhal::StatusCode GRPCVehicleHardware::getValues(
103 std::shared_ptr<const GetValuesCallback> callback,
104 const std::vector<aidlvhal::GetValueRequest>& requests) const {
105 ::grpc::ClientContext context;
106 proto::VehiclePropValueRequests protoRequests;
107 proto::GetValueResults protoResults;
108 for (const auto& request : requests) {
109 auto& protoRequest = *protoRequests.add_requests();
110 protoRequest.set_request_id(request.requestId);
111 proto_msg_converter::aidlToProto(request.prop, protoRequest.mutable_value());
112 }
113 // TODO(chenhaosjtuacm): Make it Async.
114 auto grpc_status = mGrpcStub->GetValues(&context, protoRequests, &protoResults);
115 if (!grpc_status.ok()) {
116 LOG(ERROR) << __func__ << ": GRPC GetValues Failed: " << grpc_status.error_message();
117 return aidlvhal::StatusCode::INTERNAL_ERROR;
118 }
119 std::vector<aidlvhal::GetValueResult> results;
120 for (const auto& protoResult : protoResults.results()) {
121 auto& result = results.emplace_back();
122 result.requestId = protoResult.request_id();
123 result.status = static_cast<aidlvhal::StatusCode>(protoResult.status());
124 if (protoResult.has_value()) {
125 aidlvhal::VehiclePropValue value;
126 proto_msg_converter::protoToAidl(protoResult.value(), &value);
127 result.prop = std::move(value);
128 }
129 }
130 (*callback)(std::move(results));
131
132 return aidlvhal::StatusCode::OK;
133}
134
135void GRPCVehicleHardware::registerOnPropertyChangeEvent(
136 std::unique_ptr<const PropertyChangeCallback> callback) {
137 std::lock_guard lck(mCallbackMutex);
138 if (mOnPropChange) {
139 LOG(ERROR) << __func__ << " must only be called once.";
140 return;
141 }
142 mOnPropChange = std::move(callback);
143}
144
145void GRPCVehicleHardware::registerOnPropertySetErrorEvent(
146 std::unique_ptr<const PropertySetErrorCallback> callback) {
147 std::lock_guard lck(mCallbackMutex);
148 if (mOnSetErr) {
149 LOG(ERROR) << __func__ << " must only be called once.";
150 return;
151 }
152 mOnSetErr = std::move(callback);
153}
154
Hao Chena810fb22023-04-11 15:27:44 -0700155DumpResult GRPCVehicleHardware::dump(const std::vector<std::string>& options) {
156 ::grpc::ClientContext context;
157 proto::DumpOptions protoDumpOptions;
158 proto::DumpResult protoDumpResult;
159 for (const auto& option : options) {
160 protoDumpOptions.add_options(option);
161 }
162 auto grpc_status = mGrpcStub->Dump(&context, protoDumpOptions, &protoDumpResult);
163 if (!grpc_status.ok()) {
164 LOG(ERROR) << __func__ << ": GRPC Dump Failed: " << grpc_status.error_message();
165 return {};
166 }
167 return {
168 .callerShouldDumpState = protoDumpResult.caller_should_dump_state(),
169 .buffer = protoDumpResult.buffer(),
170 };
Hao Chen6cb86892023-04-10 15:21:59 -0700171}
172
173aidlvhal::StatusCode GRPCVehicleHardware::checkHealth() {
Hao Chena810fb22023-04-11 15:27:44 -0700174 ::grpc::ClientContext context;
175 proto::VehicleHalCallStatus protoStatus;
176 auto grpc_status = mGrpcStub->CheckHealth(&context, ::google::protobuf::Empty(), &protoStatus);
177 if (!grpc_status.ok()) {
178 LOG(ERROR) << __func__ << ": GRPC CheckHealth Failed: " << grpc_status.error_message();
179 return aidlvhal::StatusCode::INTERNAL_ERROR;
180 }
181 return static_cast<aidlvhal::StatusCode>(protoStatus.status_code());
Hao Chen6cb86892023-04-10 15:21:59 -0700182}
183
Hao Chena810fb22023-04-11 15:27:44 -0700184aidlvhal::StatusCode GRPCVehicleHardware::updateSampleRate(int32_t propId, int32_t areaId,
185 float sampleRate) {
186 ::grpc::ClientContext context;
187 proto::UpdateSampleRateRequest request;
188 proto::VehicleHalCallStatus protoStatus;
189 request.set_prop(propId);
190 request.set_area_id(areaId);
191 request.set_sample_rate(sampleRate);
192 auto grpc_status = mGrpcStub->UpdateSampleRate(&context, request, &protoStatus);
193 if (!grpc_status.ok()) {
194 LOG(ERROR) << __func__ << ": GRPC UpdateSampleRate Failed: " << grpc_status.error_message();
195 return aidlvhal::StatusCode::INTERNAL_ERROR;
196 }
197 return static_cast<aidlvhal::StatusCode>(protoStatus.status_code());
Hao Chen6cb86892023-04-10 15:21:59 -0700198}
199
200bool GRPCVehicleHardware::waitForConnected(std::chrono::milliseconds waitTime) {
201 return mGrpcChannel->WaitForConnected(gpr_time_add(
202 gpr_now(GPR_CLOCK_MONOTONIC), gpr_time_from_millis(waitTime.count(), GPR_TIMESPAN)));
203}
204
205void GRPCVehicleHardware::ValuePollingLoop() {
206 while (!mShuttingDownFlag.load()) {
207 ::grpc::ClientContext context;
208
209 bool rpc_stopped{false};
210 std::thread shuttingdown_watcher([this, &rpc_stopped, &context]() {
211 std::unique_lock<std::mutex> lck(mShutdownMutex);
212 mShutdownCV.wait(lck, [this, &rpc_stopped]() {
213 return rpc_stopped || mShuttingDownFlag.load();
214 });
215 context.TryCancel();
216 });
217
218 auto value_stream =
219 mGrpcStub->StartPropertyValuesStream(&context, ::google::protobuf::Empty());
220 LOG(INFO) << __func__ << ": GRPC Value Streaming Started";
221 proto::VehiclePropValues protoValues;
222 while (!mShuttingDownFlag.load() && value_stream->Read(&protoValues)) {
223 std::vector<aidlvhal::VehiclePropValue> values;
224 for (const auto protoValue : protoValues.values()) {
225 values.push_back(aidlvhal::VehiclePropValue());
226 proto_msg_converter::protoToAidl(protoValue, &values.back());
227 }
228 std::shared_lock lck(mCallbackMutex);
229 if (mOnPropChange) {
230 (*mOnPropChange)(values);
231 }
232 }
233
234 {
235 std::lock_guard lck(mShutdownMutex);
236 rpc_stopped = true;
237 }
238 mShutdownCV.notify_all();
239 shuttingdown_watcher.join();
240
241 auto grpc_status = value_stream->Finish();
242 // never reach here until connection lost
243 LOG(ERROR) << __func__ << ": GRPC Value Streaming Failed: " << grpc_status.error_message();
244
245 // try to reconnect
246 }
247}
248
249} // namespace android::hardware::automotive::vehicle::virtualization