• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 
29 namespace android::hardware::automotive::vehicle::virtualization {
30 
getChannelCredentials()31 static std::shared_ptr<::grpc::ChannelCredentials> getChannelCredentials() {
32     // TODO(chenhaosjtuacm): get secured credentials here
33     return ::grpc::InsecureChannelCredentials();
34 }
35 
GRPCVehicleHardware(std::string service_addr)36 GRPCVehicleHardware::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 
~GRPCVehicleHardware()42 GRPCVehicleHardware::~GRPCVehicleHardware() {
43     {
44         std::lock_guard lck(mShutdownMutex);
45         mShuttingDownFlag.store(true);
46     }
47     mShutdownCV.notify_all();
48     mValuePollingThread.join();
49 }
50 
getAllPropertyConfigs() const51 std::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 
setValues(std::shared_ptr<const SetValuesCallback> callback,const std::vector<aidlvhal::SetValueRequest> & requests)69 aidlvhal::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 
getValues(std::shared_ptr<const GetValuesCallback> callback,const std::vector<aidlvhal::GetValueRequest> & requests) const102 aidlvhal::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 
registerOnPropertyChangeEvent(std::unique_ptr<const PropertyChangeCallback> callback)135 void 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 
registerOnPropertySetErrorEvent(std::unique_ptr<const PropertySetErrorCallback> callback)145 void 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 
dump(const std::vector<std::string> & options)155 DumpResult 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     };
171 }
172 
checkHealth()173 aidlvhal::StatusCode GRPCVehicleHardware::checkHealth() {
174     ::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());
182 }
183 
updateSampleRate(int32_t propId,int32_t areaId,float sampleRate)184 aidlvhal::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());
198 }
199 
waitForConnected(std::chrono::milliseconds waitTime)200 bool 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 
ValuePollingLoop()205 void 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
250