Loading automotive/vehicle/aidl/impl/grpc/Android.bp 0 → 100644 +102 −0 Original line number Diff line number Diff line // Copyright (C) 2023 The Android Open Source Project // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package { default_applicable_licenses: ["Android-Apache-2.0"], } genrule { name: "VehicleServerProtoStub_h@default-grpc", tools: [ "aprotoc", "protoc-gen-grpc-cpp-plugin", ], cmd: "$(location aprotoc) -I$$(dirname $(in)) -Ihardware/interfaces/automotive/vehicle/aidl/impl/proto -Iexternal/protobuf/src --plugin=protoc-gen-grpc=$(location protoc-gen-grpc-cpp-plugin) $(in) --grpc_out=$(genDir) --cpp_out=$(genDir)", srcs: [ "proto/VehicleServer.proto", ], out: [ "VehicleServer.pb.h", "VehicleServer.grpc.pb.h", ], visibility: ["//visibility:private"], } genrule { name: "VehicleServerProtoStub_cc@default-grpc", tools: [ "aprotoc", "protoc-gen-grpc-cpp-plugin", ], cmd: "$(location aprotoc) -I$$(dirname $(in)) -Ihardware/interfaces/automotive/vehicle/aidl/impl/proto -Iexternal/protobuf/src --plugin=protoc-gen-grpc=$(location protoc-gen-grpc-cpp-plugin) $(in) --grpc_out=$(genDir) --cpp_out=$(genDir)", srcs: [ "proto/VehicleServer.proto", ], out: [ "VehicleServer.pb.cc", "VehicleServer.grpc.pb.cc", ], visibility: ["//visibility:private"], } cc_library_static { name: "android.hardware.automotive.vehicle@default-grpc-libgrpc", vendor: true, host_supported: true, include_dirs: [ "external/protobuf/src", ], generated_headers: [ "VehicleServerProtoStub_h@default-grpc", ], export_generated_headers: [ "VehicleServerProtoStub_h@default-grpc", ], generated_sources: [ "VehicleServerProtoStub_cc@default-grpc", ], whole_static_libs: [ "VehicleHalProtos", ], shared_libs: [ "libgrpc++", ], cflags: [ "-Wno-unused-parameter", ], } cc_library_static { name: "android.hardware.automotive.vehicle@default-grpc-hardware-lib", defaults: ["VehicleHalDefaults"], vendor: true, srcs: [ "GRPCVehicleHardware.cpp", ], whole_static_libs: [ "android.hardware.automotive.vehicle@default-grpc-libgrpc", "VehicleHalProtoMessageConverter", ], header_libs: [ "IVehicleHardware", ], shared_libs: [ "libgrpc++", "libprotobuf-cpp-full", ], export_include_dirs: ["."], cflags: [ "-Wno-unused-parameter", ], } automotive/vehicle/aidl/impl/grpc/GRPCVehicleHardware.cpp 0 → 100644 +221 −0 Original line number Diff line number Diff line /* * Copyright (C) 2023 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include <GRPCVehicleHardware.h> #include "ProtoMessageConverter.h" #include <android-base/logging.h> #include <grpc++/grpc++.h> #include <cstdlib> #include <mutex> #include <shared_mutex> #include <utility> namespace android::hardware::automotive::vehicle::virtualization { static std::shared_ptr<::grpc::ChannelCredentials> getChannelCredentials() { // TODO(chenhaosjtuacm): get secured credentials here return ::grpc::InsecureChannelCredentials(); } GRPCVehicleHardware::GRPCVehicleHardware(std::string service_addr) : mServiceAddr(std::move(service_addr)), mGrpcChannel(::grpc::CreateChannel(mServiceAddr, getChannelCredentials())), mGrpcStub(proto::VehicleServer::NewStub(mGrpcChannel)), mValuePollingThread([this] { ValuePollingLoop(); }) {} GRPCVehicleHardware::~GRPCVehicleHardware() { { std::lock_guard lck(mShutdownMutex); mShuttingDownFlag.store(true); } mShutdownCV.notify_all(); mValuePollingThread.join(); } std::vector<aidlvhal::VehiclePropConfig> GRPCVehicleHardware::getAllPropertyConfigs() const { std::vector<aidlvhal::VehiclePropConfig> configs; ::grpc::ClientContext context; auto config_stream = mGrpcStub->GetAllPropertyConfig(&context, ::google::protobuf::Empty()); proto::VehiclePropConfig protoConfig; while (config_stream->Read(&protoConfig)) { aidlvhal::VehiclePropConfig config; proto_msg_converter::protoToAidl(protoConfig, &config); configs.push_back(std::move(config)); } auto grpc_status = config_stream->Finish(); if (!grpc_status.ok()) { LOG(ERROR) << __func__ << ": GRPC GetAllPropertyConfig Failed: " << grpc_status.error_message(); } return configs; } aidlvhal::StatusCode GRPCVehicleHardware::setValues( std::shared_ptr<const SetValuesCallback> callback, const std::vector<aidlvhal::SetValueRequest>& requests) { ::grpc::ClientContext context; proto::VehiclePropValueRequests protoRequests; proto::SetValueResults protoResults; for (const auto& request : requests) { auto& protoRequest = *protoRequests.add_requests(); protoRequest.set_request_id(request.requestId); proto_msg_converter::aidlToProto(request.value, protoRequest.mutable_value()); } // TODO(chenhaosjtuacm): Make it Async. auto grpc_status = mGrpcStub->SetValues(&context, protoRequests, &protoResults); if (!grpc_status.ok()) { LOG(ERROR) << __func__ << ": GRPC SetValues Failed: " << grpc_status.error_message(); { std::shared_lock lck(mCallbackMutex); // TODO(chenhaosjtuacm): call on-set-error callback. } return aidlvhal::StatusCode::INTERNAL_ERROR; } std::vector<aidlvhal::SetValueResult> results; for (const auto& protoResult : protoResults.results()) { auto& result = results.emplace_back(); result.requestId = protoResult.request_id(); result.status = static_cast<aidlvhal::StatusCode>(protoResult.status()); // TODO(chenhaosjtuacm): call on-set-error callback. } (*callback)(std::move(results)); return aidlvhal::StatusCode::OK; } aidlvhal::StatusCode GRPCVehicleHardware::getValues( std::shared_ptr<const GetValuesCallback> callback, const std::vector<aidlvhal::GetValueRequest>& requests) const { ::grpc::ClientContext context; proto::VehiclePropValueRequests protoRequests; proto::GetValueResults protoResults; for (const auto& request : requests) { auto& protoRequest = *protoRequests.add_requests(); protoRequest.set_request_id(request.requestId); proto_msg_converter::aidlToProto(request.prop, protoRequest.mutable_value()); } // TODO(chenhaosjtuacm): Make it Async. auto grpc_status = mGrpcStub->GetValues(&context, protoRequests, &protoResults); if (!grpc_status.ok()) { LOG(ERROR) << __func__ << ": GRPC GetValues Failed: " << grpc_status.error_message(); return aidlvhal::StatusCode::INTERNAL_ERROR; } std::vector<aidlvhal::GetValueResult> results; for (const auto& protoResult : protoResults.results()) { auto& result = results.emplace_back(); result.requestId = protoResult.request_id(); result.status = static_cast<aidlvhal::StatusCode>(protoResult.status()); if (protoResult.has_value()) { aidlvhal::VehiclePropValue value; proto_msg_converter::protoToAidl(protoResult.value(), &value); result.prop = std::move(value); } } (*callback)(std::move(results)); return aidlvhal::StatusCode::OK; } void GRPCVehicleHardware::registerOnPropertyChangeEvent( std::unique_ptr<const PropertyChangeCallback> callback) { std::lock_guard lck(mCallbackMutex); if (mOnPropChange) { LOG(ERROR) << __func__ << " must only be called once."; return; } mOnPropChange = std::move(callback); } void GRPCVehicleHardware::registerOnPropertySetErrorEvent( std::unique_ptr<const PropertySetErrorCallback> callback) { std::lock_guard lck(mCallbackMutex); if (mOnSetErr) { LOG(ERROR) << __func__ << " must only be called once."; return; } mOnSetErr = std::move(callback); } DumpResult GRPCVehicleHardware::dump(const std::vector<std::string>& /* options */) { // TODO(chenhaosjtuacm): To be implemented. return {}; } aidlvhal::StatusCode GRPCVehicleHardware::checkHealth() { // TODO(chenhaosjtuacm): To be implemented. return aidlvhal::StatusCode::OK; } aidlvhal::StatusCode GRPCVehicleHardware::updateSampleRate(int32_t /* propId */, int32_t /* areaId */, float /* sampleRate */) { // TODO(chenhaosjtuacm): To be implemented. return aidlvhal::StatusCode::OK; } bool GRPCVehicleHardware::waitForConnected(std::chrono::milliseconds waitTime) { return mGrpcChannel->WaitForConnected(gpr_time_add( gpr_now(GPR_CLOCK_MONOTONIC), gpr_time_from_millis(waitTime.count(), GPR_TIMESPAN))); } void GRPCVehicleHardware::ValuePollingLoop() { while (!mShuttingDownFlag.load()) { ::grpc::ClientContext context; bool rpc_stopped{false}; std::thread shuttingdown_watcher([this, &rpc_stopped, &context]() { std::unique_lock<std::mutex> lck(mShutdownMutex); mShutdownCV.wait(lck, [this, &rpc_stopped]() { return rpc_stopped || mShuttingDownFlag.load(); }); context.TryCancel(); }); auto value_stream = mGrpcStub->StartPropertyValuesStream(&context, ::google::protobuf::Empty()); LOG(INFO) << __func__ << ": GRPC Value Streaming Started"; proto::VehiclePropValues protoValues; while (!mShuttingDownFlag.load() && value_stream->Read(&protoValues)) { std::vector<aidlvhal::VehiclePropValue> values; for (const auto protoValue : protoValues.values()) { values.push_back(aidlvhal::VehiclePropValue()); proto_msg_converter::protoToAidl(protoValue, &values.back()); } std::shared_lock lck(mCallbackMutex); if (mOnPropChange) { (*mOnPropChange)(values); } } { std::lock_guard lck(mShutdownMutex); rpc_stopped = true; } mShutdownCV.notify_all(); shuttingdown_watcher.join(); auto grpc_status = value_stream->Finish(); // never reach here until connection lost LOG(ERROR) << __func__ << ": GRPC Value Streaming Failed: " << grpc_status.error_message(); // try to reconnect } } } // namespace android::hardware::automotive::vehicle::virtualization automotive/vehicle/aidl/impl/grpc/GRPCVehicleHardware.h 0 → 100644 +100 −0 Original line number Diff line number Diff line /* * Copyright (C) 2023 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include <IVehicleHardware.h> #include <VehicleHalTypes.h> #include <VehicleUtils.h> #include <android-base/result.h> #include "VehicleServer.grpc.pb.h" #include "VehicleServer.pb.h" #include <atomic> #include <chrono> #include <condition_variable> #include <memory> #include <shared_mutex> #include <string> #include <thread> #include <vector> namespace android::hardware::automotive::vehicle::virtualization { namespace aidlvhal = ::aidl::android::hardware::automotive::vehicle; class GRPCVehicleHardware : public IVehicleHardware { public: explicit GRPCVehicleHardware(std::string service_addr); ~GRPCVehicleHardware(); // Get all the property configs. std::vector<aidlvhal::VehiclePropConfig> getAllPropertyConfigs() const override; // Set property values asynchronously. Server could return before the property set requests // are sent to vehicle bus or before property set confirmation is received. The callback is // safe to be called after the function returns and is safe to be called in a different thread. aidlvhal::StatusCode setValues(std::shared_ptr<const SetValuesCallback> callback, const std::vector<aidlvhal::SetValueRequest>& requests) override; // Get property values asynchronously. Server could return before the property values are ready. // The callback is safe to be called after the function returns and is safe to be called in a // different thread. aidlvhal::StatusCode getValues( std::shared_ptr<const GetValuesCallback> callback, const std::vector<aidlvhal::GetValueRequest>& requests) const override; // Dump debug information in the server. DumpResult dump(const std::vector<std::string>& options) override; // Check whether the system is healthy, return {@code StatusCode::OK} for healthy. aidlvhal::StatusCode checkHealth() override; // Register a callback that would be called when there is a property change event from vehicle. void registerOnPropertyChangeEvent( std::unique_ptr<const PropertyChangeCallback> callback) override; // Register a callback that would be called when there is a property set error event from // vehicle. void registerOnPropertySetErrorEvent( std::unique_ptr<const PropertySetErrorCallback> callback) override; // Update the sample rate for the [propId, areaId] pair. aidlvhal::StatusCode updateSampleRate(int32_t propId, int32_t areaId, float sampleRate) override; bool waitForConnected(std::chrono::milliseconds waitTime); private: void ValuePollingLoop(); std::string mServiceAddr; std::shared_ptr<::grpc::Channel> mGrpcChannel; std::unique_ptr<proto::VehicleServer::Stub> mGrpcStub; std::thread mValuePollingThread; std::shared_mutex mCallbackMutex; std::unique_ptr<const PropertyChangeCallback> mOnPropChange; std::unique_ptr<const PropertySetErrorCallback> mOnSetErr; std::mutex mShutdownMutex; std::condition_variable mShutdownCV; std::atomic<bool> mShuttingDownFlag{false}; }; } // namespace android::hardware::automotive::vehicle::virtualization automotive/vehicle/aidl/impl/grpc/OWNERS 0 → 100644 +3 −0 Original line number Diff line number Diff line shanyu@google.com chenhaosjtuacm@google.com egranata@google.com automotive/vehicle/aidl/impl/grpc/proto/VehicleServer.proto 0 → 100644 +43 −0 Original line number Diff line number Diff line /* * Copyright (C) 2023 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ syntax = "proto3"; package android.hardware.automotive.vehicle.proto; import "android/hardware/automotive/vehicle/StatusCode.proto"; import "android/hardware/automotive/vehicle/VehiclePropConfig.proto"; import "android/hardware/automotive/vehicle/VehiclePropValue.proto"; import "android/hardware/automotive/vehicle/VehiclePropValueRequest.proto"; import "google/protobuf/empty.proto"; message VehicleHalCallStatus { StatusCode status_code = 1; } message VehiclePropValues { repeated VehiclePropValue values = 1; } service VehicleServer { rpc GetAllPropertyConfig(google.protobuf.Empty) returns (stream VehiclePropConfig) {} rpc SetValues(VehiclePropValueRequests) returns (SetValueResults) {} rpc GetValues(VehiclePropValueRequests) returns (GetValueResults) {} rpc StartPropertyValuesStream(google.protobuf.Empty) returns (stream VehiclePropValues) {} } Loading
automotive/vehicle/aidl/impl/grpc/Android.bp 0 → 100644 +102 −0 Original line number Diff line number Diff line // Copyright (C) 2023 The Android Open Source Project // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package { default_applicable_licenses: ["Android-Apache-2.0"], } genrule { name: "VehicleServerProtoStub_h@default-grpc", tools: [ "aprotoc", "protoc-gen-grpc-cpp-plugin", ], cmd: "$(location aprotoc) -I$$(dirname $(in)) -Ihardware/interfaces/automotive/vehicle/aidl/impl/proto -Iexternal/protobuf/src --plugin=protoc-gen-grpc=$(location protoc-gen-grpc-cpp-plugin) $(in) --grpc_out=$(genDir) --cpp_out=$(genDir)", srcs: [ "proto/VehicleServer.proto", ], out: [ "VehicleServer.pb.h", "VehicleServer.grpc.pb.h", ], visibility: ["//visibility:private"], } genrule { name: "VehicleServerProtoStub_cc@default-grpc", tools: [ "aprotoc", "protoc-gen-grpc-cpp-plugin", ], cmd: "$(location aprotoc) -I$$(dirname $(in)) -Ihardware/interfaces/automotive/vehicle/aidl/impl/proto -Iexternal/protobuf/src --plugin=protoc-gen-grpc=$(location protoc-gen-grpc-cpp-plugin) $(in) --grpc_out=$(genDir) --cpp_out=$(genDir)", srcs: [ "proto/VehicleServer.proto", ], out: [ "VehicleServer.pb.cc", "VehicleServer.grpc.pb.cc", ], visibility: ["//visibility:private"], } cc_library_static { name: "android.hardware.automotive.vehicle@default-grpc-libgrpc", vendor: true, host_supported: true, include_dirs: [ "external/protobuf/src", ], generated_headers: [ "VehicleServerProtoStub_h@default-grpc", ], export_generated_headers: [ "VehicleServerProtoStub_h@default-grpc", ], generated_sources: [ "VehicleServerProtoStub_cc@default-grpc", ], whole_static_libs: [ "VehicleHalProtos", ], shared_libs: [ "libgrpc++", ], cflags: [ "-Wno-unused-parameter", ], } cc_library_static { name: "android.hardware.automotive.vehicle@default-grpc-hardware-lib", defaults: ["VehicleHalDefaults"], vendor: true, srcs: [ "GRPCVehicleHardware.cpp", ], whole_static_libs: [ "android.hardware.automotive.vehicle@default-grpc-libgrpc", "VehicleHalProtoMessageConverter", ], header_libs: [ "IVehicleHardware", ], shared_libs: [ "libgrpc++", "libprotobuf-cpp-full", ], export_include_dirs: ["."], cflags: [ "-Wno-unused-parameter", ], }
automotive/vehicle/aidl/impl/grpc/GRPCVehicleHardware.cpp 0 → 100644 +221 −0 Original line number Diff line number Diff line /* * Copyright (C) 2023 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include <GRPCVehicleHardware.h> #include "ProtoMessageConverter.h" #include <android-base/logging.h> #include <grpc++/grpc++.h> #include <cstdlib> #include <mutex> #include <shared_mutex> #include <utility> namespace android::hardware::automotive::vehicle::virtualization { static std::shared_ptr<::grpc::ChannelCredentials> getChannelCredentials() { // TODO(chenhaosjtuacm): get secured credentials here return ::grpc::InsecureChannelCredentials(); } GRPCVehicleHardware::GRPCVehicleHardware(std::string service_addr) : mServiceAddr(std::move(service_addr)), mGrpcChannel(::grpc::CreateChannel(mServiceAddr, getChannelCredentials())), mGrpcStub(proto::VehicleServer::NewStub(mGrpcChannel)), mValuePollingThread([this] { ValuePollingLoop(); }) {} GRPCVehicleHardware::~GRPCVehicleHardware() { { std::lock_guard lck(mShutdownMutex); mShuttingDownFlag.store(true); } mShutdownCV.notify_all(); mValuePollingThread.join(); } std::vector<aidlvhal::VehiclePropConfig> GRPCVehicleHardware::getAllPropertyConfigs() const { std::vector<aidlvhal::VehiclePropConfig> configs; ::grpc::ClientContext context; auto config_stream = mGrpcStub->GetAllPropertyConfig(&context, ::google::protobuf::Empty()); proto::VehiclePropConfig protoConfig; while (config_stream->Read(&protoConfig)) { aidlvhal::VehiclePropConfig config; proto_msg_converter::protoToAidl(protoConfig, &config); configs.push_back(std::move(config)); } auto grpc_status = config_stream->Finish(); if (!grpc_status.ok()) { LOG(ERROR) << __func__ << ": GRPC GetAllPropertyConfig Failed: " << grpc_status.error_message(); } return configs; } aidlvhal::StatusCode GRPCVehicleHardware::setValues( std::shared_ptr<const SetValuesCallback> callback, const std::vector<aidlvhal::SetValueRequest>& requests) { ::grpc::ClientContext context; proto::VehiclePropValueRequests protoRequests; proto::SetValueResults protoResults; for (const auto& request : requests) { auto& protoRequest = *protoRequests.add_requests(); protoRequest.set_request_id(request.requestId); proto_msg_converter::aidlToProto(request.value, protoRequest.mutable_value()); } // TODO(chenhaosjtuacm): Make it Async. auto grpc_status = mGrpcStub->SetValues(&context, protoRequests, &protoResults); if (!grpc_status.ok()) { LOG(ERROR) << __func__ << ": GRPC SetValues Failed: " << grpc_status.error_message(); { std::shared_lock lck(mCallbackMutex); // TODO(chenhaosjtuacm): call on-set-error callback. } return aidlvhal::StatusCode::INTERNAL_ERROR; } std::vector<aidlvhal::SetValueResult> results; for (const auto& protoResult : protoResults.results()) { auto& result = results.emplace_back(); result.requestId = protoResult.request_id(); result.status = static_cast<aidlvhal::StatusCode>(protoResult.status()); // TODO(chenhaosjtuacm): call on-set-error callback. } (*callback)(std::move(results)); return aidlvhal::StatusCode::OK; } aidlvhal::StatusCode GRPCVehicleHardware::getValues( std::shared_ptr<const GetValuesCallback> callback, const std::vector<aidlvhal::GetValueRequest>& requests) const { ::grpc::ClientContext context; proto::VehiclePropValueRequests protoRequests; proto::GetValueResults protoResults; for (const auto& request : requests) { auto& protoRequest = *protoRequests.add_requests(); protoRequest.set_request_id(request.requestId); proto_msg_converter::aidlToProto(request.prop, protoRequest.mutable_value()); } // TODO(chenhaosjtuacm): Make it Async. auto grpc_status = mGrpcStub->GetValues(&context, protoRequests, &protoResults); if (!grpc_status.ok()) { LOG(ERROR) << __func__ << ": GRPC GetValues Failed: " << grpc_status.error_message(); return aidlvhal::StatusCode::INTERNAL_ERROR; } std::vector<aidlvhal::GetValueResult> results; for (const auto& protoResult : protoResults.results()) { auto& result = results.emplace_back(); result.requestId = protoResult.request_id(); result.status = static_cast<aidlvhal::StatusCode>(protoResult.status()); if (protoResult.has_value()) { aidlvhal::VehiclePropValue value; proto_msg_converter::protoToAidl(protoResult.value(), &value); result.prop = std::move(value); } } (*callback)(std::move(results)); return aidlvhal::StatusCode::OK; } void GRPCVehicleHardware::registerOnPropertyChangeEvent( std::unique_ptr<const PropertyChangeCallback> callback) { std::lock_guard lck(mCallbackMutex); if (mOnPropChange) { LOG(ERROR) << __func__ << " must only be called once."; return; } mOnPropChange = std::move(callback); } void GRPCVehicleHardware::registerOnPropertySetErrorEvent( std::unique_ptr<const PropertySetErrorCallback> callback) { std::lock_guard lck(mCallbackMutex); if (mOnSetErr) { LOG(ERROR) << __func__ << " must only be called once."; return; } mOnSetErr = std::move(callback); } DumpResult GRPCVehicleHardware::dump(const std::vector<std::string>& /* options */) { // TODO(chenhaosjtuacm): To be implemented. return {}; } aidlvhal::StatusCode GRPCVehicleHardware::checkHealth() { // TODO(chenhaosjtuacm): To be implemented. return aidlvhal::StatusCode::OK; } aidlvhal::StatusCode GRPCVehicleHardware::updateSampleRate(int32_t /* propId */, int32_t /* areaId */, float /* sampleRate */) { // TODO(chenhaosjtuacm): To be implemented. return aidlvhal::StatusCode::OK; } bool GRPCVehicleHardware::waitForConnected(std::chrono::milliseconds waitTime) { return mGrpcChannel->WaitForConnected(gpr_time_add( gpr_now(GPR_CLOCK_MONOTONIC), gpr_time_from_millis(waitTime.count(), GPR_TIMESPAN))); } void GRPCVehicleHardware::ValuePollingLoop() { while (!mShuttingDownFlag.load()) { ::grpc::ClientContext context; bool rpc_stopped{false}; std::thread shuttingdown_watcher([this, &rpc_stopped, &context]() { std::unique_lock<std::mutex> lck(mShutdownMutex); mShutdownCV.wait(lck, [this, &rpc_stopped]() { return rpc_stopped || mShuttingDownFlag.load(); }); context.TryCancel(); }); auto value_stream = mGrpcStub->StartPropertyValuesStream(&context, ::google::protobuf::Empty()); LOG(INFO) << __func__ << ": GRPC Value Streaming Started"; proto::VehiclePropValues protoValues; while (!mShuttingDownFlag.load() && value_stream->Read(&protoValues)) { std::vector<aidlvhal::VehiclePropValue> values; for (const auto protoValue : protoValues.values()) { values.push_back(aidlvhal::VehiclePropValue()); proto_msg_converter::protoToAidl(protoValue, &values.back()); } std::shared_lock lck(mCallbackMutex); if (mOnPropChange) { (*mOnPropChange)(values); } } { std::lock_guard lck(mShutdownMutex); rpc_stopped = true; } mShutdownCV.notify_all(); shuttingdown_watcher.join(); auto grpc_status = value_stream->Finish(); // never reach here until connection lost LOG(ERROR) << __func__ << ": GRPC Value Streaming Failed: " << grpc_status.error_message(); // try to reconnect } } } // namespace android::hardware::automotive::vehicle::virtualization
automotive/vehicle/aidl/impl/grpc/GRPCVehicleHardware.h 0 → 100644 +100 −0 Original line number Diff line number Diff line /* * Copyright (C) 2023 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include <IVehicleHardware.h> #include <VehicleHalTypes.h> #include <VehicleUtils.h> #include <android-base/result.h> #include "VehicleServer.grpc.pb.h" #include "VehicleServer.pb.h" #include <atomic> #include <chrono> #include <condition_variable> #include <memory> #include <shared_mutex> #include <string> #include <thread> #include <vector> namespace android::hardware::automotive::vehicle::virtualization { namespace aidlvhal = ::aidl::android::hardware::automotive::vehicle; class GRPCVehicleHardware : public IVehicleHardware { public: explicit GRPCVehicleHardware(std::string service_addr); ~GRPCVehicleHardware(); // Get all the property configs. std::vector<aidlvhal::VehiclePropConfig> getAllPropertyConfigs() const override; // Set property values asynchronously. Server could return before the property set requests // are sent to vehicle bus or before property set confirmation is received. The callback is // safe to be called after the function returns and is safe to be called in a different thread. aidlvhal::StatusCode setValues(std::shared_ptr<const SetValuesCallback> callback, const std::vector<aidlvhal::SetValueRequest>& requests) override; // Get property values asynchronously. Server could return before the property values are ready. // The callback is safe to be called after the function returns and is safe to be called in a // different thread. aidlvhal::StatusCode getValues( std::shared_ptr<const GetValuesCallback> callback, const std::vector<aidlvhal::GetValueRequest>& requests) const override; // Dump debug information in the server. DumpResult dump(const std::vector<std::string>& options) override; // Check whether the system is healthy, return {@code StatusCode::OK} for healthy. aidlvhal::StatusCode checkHealth() override; // Register a callback that would be called when there is a property change event from vehicle. void registerOnPropertyChangeEvent( std::unique_ptr<const PropertyChangeCallback> callback) override; // Register a callback that would be called when there is a property set error event from // vehicle. void registerOnPropertySetErrorEvent( std::unique_ptr<const PropertySetErrorCallback> callback) override; // Update the sample rate for the [propId, areaId] pair. aidlvhal::StatusCode updateSampleRate(int32_t propId, int32_t areaId, float sampleRate) override; bool waitForConnected(std::chrono::milliseconds waitTime); private: void ValuePollingLoop(); std::string mServiceAddr; std::shared_ptr<::grpc::Channel> mGrpcChannel; std::unique_ptr<proto::VehicleServer::Stub> mGrpcStub; std::thread mValuePollingThread; std::shared_mutex mCallbackMutex; std::unique_ptr<const PropertyChangeCallback> mOnPropChange; std::unique_ptr<const PropertySetErrorCallback> mOnSetErr; std::mutex mShutdownMutex; std::condition_variable mShutdownCV; std::atomic<bool> mShuttingDownFlag{false}; }; } // namespace android::hardware::automotive::vehicle::virtualization
automotive/vehicle/aidl/impl/grpc/OWNERS 0 → 100644 +3 −0 Original line number Diff line number Diff line shanyu@google.com chenhaosjtuacm@google.com egranata@google.com
automotive/vehicle/aidl/impl/grpc/proto/VehicleServer.proto 0 → 100644 +43 −0 Original line number Diff line number Diff line /* * Copyright (C) 2023 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ syntax = "proto3"; package android.hardware.automotive.vehicle.proto; import "android/hardware/automotive/vehicle/StatusCode.proto"; import "android/hardware/automotive/vehicle/VehiclePropConfig.proto"; import "android/hardware/automotive/vehicle/VehiclePropValue.proto"; import "android/hardware/automotive/vehicle/VehiclePropValueRequest.proto"; import "google/protobuf/empty.proto"; message VehicleHalCallStatus { StatusCode status_code = 1; } message VehiclePropValues { repeated VehiclePropValue values = 1; } service VehicleServer { rpc GetAllPropertyConfig(google.protobuf.Empty) returns (stream VehiclePropConfig) {} rpc SetValues(VehiclePropValueRequests) returns (SetValueResults) {} rpc GetValues(VehiclePropValueRequests) returns (GetValueResults) {} rpc StartPropertyValuesStream(google.protobuf.Empty) returns (stream VehiclePropValues) {} }