From 32d467066a5e8c1880635fbe5224c6b9fb4350b4 Mon Sep 17 00:00:00 2001 From: Hao Chen Date: Mon, 10 Apr 2023 15:59:50 -0700 Subject: [PATCH 1/2] GRPC Vehicle Proxy Server The GRPC proxy server speaks to another IVehicleHardware (no matter if it is real or fake) to serve other GRPC vehicle hardware(s). It can be used as a real GRPC Vehicle Hardware backend when it is running on the machine that have a direct access to the real vehicle bus, or it can also be used as a fake backend for testing. Test: `atest GRPCVehicleProxyServerUnitTest` Bug: 266001013 Change-Id: Ifec6e21223986a68ab089a87a9664c1b52601ea2 --- automotive/vehicle/aidl/impl/grpc/Android.bp | 24 ++ .../aidl/impl/grpc/GRPCVehicleProxyServer.cpp | 269 ++++++++++++++++++ .../aidl/impl/grpc/GRPCVehicleProxyServer.h | 112 ++++++++ .../vehicle/aidl/impl/grpc/test/Android.bp | 28 ++ .../test/GRPCVehicleProxyServerUnitTest.cpp | 147 ++++++++++ 5 files changed, 580 insertions(+) create mode 100644 automotive/vehicle/aidl/impl/grpc/GRPCVehicleProxyServer.cpp create mode 100644 automotive/vehicle/aidl/impl/grpc/GRPCVehicleProxyServer.h create mode 100644 automotive/vehicle/aidl/impl/grpc/test/GRPCVehicleProxyServerUnitTest.cpp diff --git a/automotive/vehicle/aidl/impl/grpc/Android.bp b/automotive/vehicle/aidl/impl/grpc/Android.bp index e8f0970c4d..06c9600100 100644 --- a/automotive/vehicle/aidl/impl/grpc/Android.bp +++ b/automotive/vehicle/aidl/impl/grpc/Android.bp @@ -100,3 +100,27 @@ cc_library_static { "-Wno-unused-parameter", ], } + +cc_library_static { + name: "android.hardware.automotive.vehicle@default-grpc-server-lib", + defaults: ["VehicleHalDefaults"], + vendor: true, + srcs: [ + "GRPCVehicleProxyServer.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", + ], +} diff --git a/automotive/vehicle/aidl/impl/grpc/GRPCVehicleProxyServer.cpp b/automotive/vehicle/aidl/impl/grpc/GRPCVehicleProxyServer.cpp new file mode 100644 index 0000000000..e2fe97b1c7 --- /dev/null +++ b/automotive/vehicle/aidl/impl/grpc/GRPCVehicleProxyServer.cpp @@ -0,0 +1,269 @@ +/* + * 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 "GRPCVehicleProxyServer.h" + +#include "ProtoMessageConverter.h" + +#include + +#include + +#include +#include +#include +#include +#include +#include + +namespace android::hardware::automotive::vehicle::virtualization { + +std::atomic GrpcVehicleProxyServer::ConnectionDescriptor::connection_id_counter_{0}; + +static std::shared_ptr<::grpc::ServerCredentials> getServerCredentials() { + // TODO(chenhaosjtuacm): get secured credentials here + return ::grpc::InsecureServerCredentials(); +} + +GrpcVehicleProxyServer::GrpcVehicleProxyServer(std::string serverAddr, + std::unique_ptr&& hardware) + : mServiceAddr(std::move(serverAddr)), mHardware(std::move(hardware)) { + mHardware->registerOnPropertyChangeEvent( + std::make_unique( + [this](std::vector values) { + OnVehiclePropChange(values); + })); +} + +::grpc::Status GrpcVehicleProxyServer::GetAllPropertyConfig( + ::grpc::ServerContext* context, const ::google::protobuf::Empty* request, + ::grpc::ServerWriter* stream) { + for (const auto& config : mHardware->getAllPropertyConfigs()) { + proto::VehiclePropConfig protoConfig; + proto_msg_converter::aidlToProto(config, &protoConfig); + if (!stream->Write(protoConfig)) { + return ::grpc::Status(::grpc::StatusCode::ABORTED, "Connection lost."); + } + } + return ::grpc::Status::OK; +} + +::grpc::Status GrpcVehicleProxyServer::SetValues(::grpc::ServerContext* context, + const proto::VehiclePropValueRequests* requests, + proto::SetValueResults* results) { + std::vector aidlRequests; + for (const auto& protoRequest : requests->requests()) { + auto& aidlRequest = aidlRequests.emplace_back(); + aidlRequest.requestId = protoRequest.request_id(); + proto_msg_converter::protoToAidl(protoRequest.value(), &aidlRequest.value); + } + auto waitMtx = std::make_shared(); + auto waitCV = std::make_shared(); + auto complete = std::make_shared(false); + auto tmpResults = std::make_shared(); + auto aidlStatus = mHardware->setValues( + std::make_shared( + [waitMtx, waitCV, complete, + tmpResults](std::vector setValueResults) { + for (const auto& aidlResult : setValueResults) { + auto& protoResult = *tmpResults->add_results(); + protoResult.set_request_id(aidlResult.requestId); + protoResult.set_status( + static_cast(aidlResult.status)); + } + { + std::lock_guard lck(*waitMtx); + *complete = true; + } + waitCV->notify_all(); + }), + aidlRequests); + if (aidlStatus != aidlvhal::StatusCode::OK) { + return ::grpc::Status(::grpc::StatusCode::INTERNAL, + "The underlying hardware fails to set values, VHAL status: " + + toString(aidlStatus)); + } + std::unique_lock lck(*waitMtx); + bool success = waitCV->wait_for(lck, kHardwareOpTimeout, [complete] { return *complete; }); + if (!success) { + return ::grpc::Status(::grpc::StatusCode::INTERNAL, + "The underlying hardware set values timeout."); + } + *results = std::move(*tmpResults); + return ::grpc::Status::OK; +} + +::grpc::Status GrpcVehicleProxyServer::GetValues(::grpc::ServerContext* context, + const proto::VehiclePropValueRequests* requests, + proto::GetValueResults* results) { + std::vector aidlRequests; + for (const auto& protoRequest : requests->requests()) { + auto& aidlRequest = aidlRequests.emplace_back(); + aidlRequest.requestId = protoRequest.request_id(); + proto_msg_converter::protoToAidl(protoRequest.value(), &aidlRequest.prop); + } + auto waitMtx = std::make_shared(); + auto waitCV = std::make_shared(); + auto complete = std::make_shared(false); + auto tmpResults = std::make_shared(); + auto aidlStatus = mHardware->getValues( + std::make_shared( + [waitMtx, waitCV, complete, + tmpResults](std::vector getValueResults) { + for (const auto& aidlResult : getValueResults) { + auto& protoResult = *tmpResults->add_results(); + protoResult.set_request_id(aidlResult.requestId); + protoResult.set_status( + static_cast(aidlResult.status)); + if (aidlResult.prop) { + auto* valuePtr = protoResult.mutable_value(); + proto_msg_converter::aidlToProto(*aidlResult.prop, valuePtr); + } + } + { + std::lock_guard lck(*waitMtx); + *complete = true; + } + waitCV->notify_all(); + }), + aidlRequests); + if (aidlStatus != aidlvhal::StatusCode::OK) { + return ::grpc::Status(::grpc::StatusCode::INTERNAL, + "The underlying hardware fails to get values, VHAL status: " + + toString(aidlStatus)); + } + std::unique_lock lck(*waitMtx); + bool success = waitCV->wait_for(lck, kHardwareOpTimeout, [complete] { return *complete; }); + if (!success) { + return ::grpc::Status(::grpc::StatusCode::INTERNAL, + "The underlying hardware get values timeout."); + } + *results = std::move(*tmpResults); + return ::grpc::Status::OK; +} + +::grpc::Status GrpcVehicleProxyServer::StartPropertyValuesStream( + ::grpc::ServerContext* context, const ::google::protobuf::Empty* request, + ::grpc::ServerWriter* stream) { + auto conn = std::make_shared(stream); + { + std::lock_guard lck(mConnectionMutex); + mValueStreamingConnections.push_back(conn); + } + conn->Wait(); + LOG(ERROR) << __func__ << ": Stream lost, ID : " << conn->ID(); + return ::grpc::Status(::grpc::StatusCode::ABORTED, "Connection lost."); +} + +void GrpcVehicleProxyServer::OnVehiclePropChange( + const std::vector& values) { + std::unordered_set brokenConn; + proto::VehiclePropValues protoValues; + for (const auto& value : values) { + auto* protoValuePtr = protoValues.add_values(); + proto_msg_converter::aidlToProto(value, protoValuePtr); + } + { + std::shared_lock read_lock(mConnectionMutex); + for (auto& connection : mValueStreamingConnections) { + auto writeOK = connection->Write(protoValues); + if (!writeOK) { + LOG(ERROR) << __func__ + << ": Server Write failed, connection lost. ID: " << connection->ID(); + brokenConn.insert(connection->ID()); + } + } + } + if (brokenConn.empty()) { + return; + } + std::unique_lock write_lock(mConnectionMutex); + mValueStreamingConnections.erase( + std::remove_if(mValueStreamingConnections.begin(), mValueStreamingConnections.end(), + [&brokenConn](const auto& conn) { + return brokenConn.find(conn->ID()) != brokenConn.end(); + }), + mValueStreamingConnections.end()); +} + +GrpcVehicleProxyServer& GrpcVehicleProxyServer::Start() { + if (mServer) { + LOG(WARNING) << __func__ << ": GrpcVehicleProxyServer has already started."; + return *this; + } + ::grpc::ServerBuilder builder; + builder.RegisterService(this); + builder.AddListeningPort(mServiceAddr, getServerCredentials()); + mServer = builder.BuildAndStart(); + CHECK(mServer) << __func__ << ": failed to create the GRPC server, " + << "please make sure the configuration and permissions are correct"; + return *this; +} + +GrpcVehicleProxyServer& GrpcVehicleProxyServer::Shutdown() { + std::shared_lock read_lock(mConnectionMutex); + for (auto& conn : mValueStreamingConnections) { + conn->Shutdown(); + } + if (mServer) { + mServer->Shutdown(); + } + return *this; +} + +void GrpcVehicleProxyServer::Wait() { + if (mServer) { + mServer->Wait(); + } + mServer.reset(); +} + +GrpcVehicleProxyServer::ConnectionDescriptor::~ConnectionDescriptor() { + Shutdown(); +} + +bool GrpcVehicleProxyServer::ConnectionDescriptor::Write(const proto::VehiclePropValues& values) { + if (!mStream) { + LOG(ERROR) << __func__ << ": Empty stream. ID: " << ID(); + Shutdown(); + return false; + } + { + std::lock_guard lck(*mMtx); + if (!mShutdownFlag && mStream->Write(values)) { + return true; + } else { + LOG(ERROR) << __func__ << ": Server Write failed, connection lost. ID: " << ID(); + } + } + Shutdown(); + return false; +} + +void GrpcVehicleProxyServer::ConnectionDescriptor::Wait() { + std::unique_lock lck(*mMtx); + mCV->wait(lck, [this] { return mShutdownFlag; }); +} + +void GrpcVehicleProxyServer::ConnectionDescriptor::Shutdown() { + { + std::lock_guard lck(*mMtx); + mShutdownFlag = true; + } + mCV->notify_all(); +} + +} // namespace android::hardware::automotive::vehicle::virtualization diff --git a/automotive/vehicle/aidl/impl/grpc/GRPCVehicleProxyServer.h b/automotive/vehicle/aidl/impl/grpc/GRPCVehicleProxyServer.h new file mode 100644 index 0000000000..01beec3949 --- /dev/null +++ b/automotive/vehicle/aidl/impl/grpc/GRPCVehicleProxyServer.h @@ -0,0 +1,112 @@ +/* + * 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 "VehicleServer.grpc.pb.h" +#include "VehicleServer.pb.h" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace android::hardware::automotive::vehicle::virtualization { + +namespace aidlvhal = ::aidl::android::hardware::automotive::vehicle; + +// Connect other GRPC vehicle hardware(s) to the underlying vehicle hardware. +class GrpcVehicleProxyServer : public proto::VehicleServer::Service { + public: + GrpcVehicleProxyServer(std::string serverAddr, std::unique_ptr&& hardware); + + ::grpc::Status GetAllPropertyConfig( + ::grpc::ServerContext* context, const ::google::protobuf::Empty* request, + ::grpc::ServerWriter* stream) override; + + ::grpc::Status SetValues(::grpc::ServerContext* context, + const proto::VehiclePropValueRequests* requests, + proto::SetValueResults* results) override; + + ::grpc::Status GetValues(::grpc::ServerContext* context, + const proto::VehiclePropValueRequests* requests, + proto::GetValueResults* results) override; + + ::grpc::Status StartPropertyValuesStream( + ::grpc::ServerContext* context, const ::google::protobuf::Empty* request, + ::grpc::ServerWriter* stream) override; + + GrpcVehicleProxyServer& Start(); + + GrpcVehicleProxyServer& Shutdown(); + + void Wait(); + + private: + void OnVehiclePropChange(const std::vector& values); + + // We keep long-lasting connection for streaming the prop values. + struct ConnectionDescriptor { + explicit ConnectionDescriptor(::grpc::ServerWriter* stream) + : mStream(stream), + mConnectionID(connection_id_counter_.fetch_add(1) + 1), + mMtx(std::make_unique()), + mCV(std::make_unique()) {} + + ConnectionDescriptor(const ConnectionDescriptor&) = delete; + ConnectionDescriptor(ConnectionDescriptor&& cd) = default; + ConnectionDescriptor& operator=(const ConnectionDescriptor&) = delete; + ConnectionDescriptor& operator=(ConnectionDescriptor&& cd) = default; + + ~ConnectionDescriptor(); + + uint64_t ID() const { return mConnectionID; } + + bool Write(const proto::VehiclePropValues& values); + + void Wait(); + + void Shutdown(); + + private: + ::grpc::ServerWriter* mStream; + uint64_t mConnectionID{0}; + std::unique_ptr mMtx; + std::unique_ptr mCV; + bool mShutdownFlag{false}; + + static std::atomic connection_id_counter_; + }; + + std::string mServiceAddr; + std::unique_ptr<::grpc::Server> mServer{nullptr}; + std::unique_ptr mHardware; + + std::shared_mutex mConnectionMutex; + std::vector> mValueStreamingConnections; + + static constexpr auto kHardwareOpTimeout = std::chrono::seconds(1); +}; + +} // namespace android::hardware::automotive::vehicle::virtualization diff --git a/automotive/vehicle/aidl/impl/grpc/test/Android.bp b/automotive/vehicle/aidl/impl/grpc/test/Android.bp index efdf4ca3c1..e53826f7f3 100644 --- a/automotive/vehicle/aidl/impl/grpc/test/Android.bp +++ b/automotive/vehicle/aidl/impl/grpc/test/Android.bp @@ -44,3 +44,31 @@ cc_test { ], test_suites: ["device-tests"], } + +cc_test { + name: "GRPCVehicleProxyServerUnitTest", + vendor: true, + srcs: ["GRPCVehicleProxyServerUnitTest.cpp"], + header_libs: [ + "IVehicleHardware", + ], + static_libs: [ + "android.hardware.automotive.vehicle@default-grpc-hardware-lib", + "android.hardware.automotive.vehicle@default-grpc-server-lib", + "libgtest", + "libgmock", + ], + shared_libs: [ + "libgrpc++", + "libprotobuf-cpp-full", + ], + // libgrpc++.so is installed as root, require root to access it. + require_root: true, + defaults: [ + "VehicleHalDefaults", + ], + cflags: [ + "-Wno-unused-parameter", + ], + test_suites: ["device-tests"], +} diff --git a/automotive/vehicle/aidl/impl/grpc/test/GRPCVehicleProxyServerUnitTest.cpp b/automotive/vehicle/aidl/impl/grpc/test/GRPCVehicleProxyServerUnitTest.cpp new file mode 100644 index 0000000000..49e6fc9d21 --- /dev/null +++ b/automotive/vehicle/aidl/impl/grpc/test/GRPCVehicleProxyServerUnitTest.cpp @@ -0,0 +1,147 @@ +// 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 "GRPCVehicleProxyServer.h" +#include "IVehicleHardware.h" +#include "VehicleServer.grpc.pb.h" +#include "VehicleServer.pb.h" + +#include +#include +#include + +#include +#include +#include +#include +#include + +namespace android::hardware::automotive::vehicle::virtualization { + +const std::string kFakeServerAddr = "0.0.0.0:54321"; + +class VehicleHardwareForTest : public IVehicleHardware { + public: + void registerOnPropertyChangeEvent( + std::unique_ptr callback) override { + mOnProp = std::move(callback); + } + + void onPropertyEvent( + std::vector values) { + if (mOnProp) { + (*mOnProp)(std::move(values)); + } + } + + // Functions that we do not care. + std::vector + getAllPropertyConfigs() const override { + return {}; + } + + aidl::android::hardware::automotive::vehicle::StatusCode setValues( + std::shared_ptr callback, + const std::vector& + requests) override { + return aidl::android::hardware::automotive::vehicle::StatusCode::OK; + } + + aidl::android::hardware::automotive::vehicle::StatusCode getValues( + std::shared_ptr callback, + const std::vector& + requests) const override { + return aidl::android::hardware::automotive::vehicle::StatusCode::OK; + } + + DumpResult dump(const std::vector& options) override { return {}; } + + aidl::android::hardware::automotive::vehicle::StatusCode checkHealth() override { + return aidl::android::hardware::automotive::vehicle::StatusCode::OK; + } + + void registerOnPropertySetErrorEvent( + std::unique_ptr callback) override {} + + private: + std::unique_ptr mOnProp; +}; + +TEST(GRPCVehicleProxyServerUnitTest, ClientConnectDisconnect) { + auto testHardware = std::make_unique(); + // HACK: manipulate the underlying hardware via raw pointer for testing. + auto* testHardwareRaw = testHardware.get(); + auto vehicleServer = + std::make_unique(kFakeServerAddr, std::move(testHardware)); + vehicleServer->Start(); + + constexpr auto kWaitForConnectionMaxTime = std::chrono::seconds(5); + constexpr auto kWaitForStreamStartTime = std::chrono::seconds(1); + constexpr auto kWaitForUpdateDeliveryTime = std::chrono::milliseconds(100); + + auto updateReceived1 = std::make_shared(false); + auto vehicleHardware1 = std::make_unique(kFakeServerAddr); + vehicleHardware1->registerOnPropertyChangeEvent( + std::make_unique( + [updateReceived1](const auto&) { *updateReceived1 = true; })); + EXPECT_TRUE(vehicleHardware1->waitForConnected(kWaitForConnectionMaxTime)); + std::this_thread::sleep_for(kWaitForStreamStartTime); + + // Client hardware 1 received update from the server. + EXPECT_FALSE(*updateReceived1); + testHardwareRaw->onPropertyEvent({}); + // Wait for the update delivery. + std::this_thread::sleep_for(kWaitForUpdateDeliveryTime); + EXPECT_TRUE(*updateReceived1); + + // Reset. + *updateReceived1 = false; + + auto updateReceived2 = std::make_shared(false); + auto vehicleHardware2 = std::make_unique(kFakeServerAddr); + vehicleHardware2->registerOnPropertyChangeEvent( + std::make_unique( + [updateReceived2](const auto&) { *updateReceived2 = true; })); + EXPECT_TRUE(vehicleHardware2->waitForConnected(kWaitForConnectionMaxTime)); + std::this_thread::sleep_for(kWaitForStreamStartTime); + + // Both client hardware 1 and 2 received update from the server. + EXPECT_FALSE(*updateReceived1); + EXPECT_FALSE(*updateReceived2); + testHardwareRaw->onPropertyEvent({}); + // Wait for the update delivery. + std::this_thread::sleep_for(kWaitForUpdateDeliveryTime); + EXPECT_TRUE(*updateReceived1); + EXPECT_TRUE(*updateReceived2); + + // Reset. + *updateReceived1 = false; + *updateReceived2 = false; + + vehicleHardware1.reset(); + + // Client 1 exited, only client hardware 2 received update from the server. + EXPECT_FALSE(*updateReceived1); + EXPECT_FALSE(*updateReceived2); + testHardwareRaw->onPropertyEvent({}); + // Wait for the update delivery. + std::this_thread::sleep_for(kWaitForUpdateDeliveryTime); + EXPECT_FALSE(*updateReceived1); + EXPECT_TRUE(*updateReceived2); + + vehicleServer->Shutdown().Wait(); +} + +} // namespace android::hardware::automotive::vehicle::virtualization From a810fb25836706ba36af68cad30281f490b88b84 Mon Sep 17 00:00:00 2001 From: Hao Chen Date: Tue, 11 Apr 2023 15:27:44 -0700 Subject: [PATCH 2/2] Complete VHAL GRPC Interfaces Add missing operations from IVehicleHardware.h Bug: 266001013 Test: `atest GRPCVehicleHardwareUnitTest GRPCVehicleProxyServerUnitTest` Change-Id: Ida3533dedce49c49c4762b2f9a43997317f5d2c4 --- .../aidl/impl/grpc/GRPCVehicleHardware.cpp | 48 +++++++++++++++---- .../aidl/impl/grpc/GRPCVehicleProxyServer.cpp | 27 +++++++++++ .../aidl/impl/grpc/GRPCVehicleProxyServer.h | 10 ++++ .../aidl/impl/grpc/proto/VehicleServer.proto | 16 +++---- automotive/vehicle/aidl/impl/proto/Android.bp | 2 + .../automotive/vehicle/DumpOptions.proto | 23 +++++++++ .../automotive/vehicle/StatusCode.proto | 4 ++ .../automotive/vehicle/VehiclePropValue.proto | 4 ++ .../vehicle/VehiclePropValueRequest.proto | 11 +++++ 9 files changed, 127 insertions(+), 18 deletions(-) create mode 100644 automotive/vehicle/aidl/impl/proto/android/hardware/automotive/vehicle/DumpOptions.proto diff --git a/automotive/vehicle/aidl/impl/grpc/GRPCVehicleHardware.cpp b/automotive/vehicle/aidl/impl/grpc/GRPCVehicleHardware.cpp index 015157d425..07422835d2 100644 --- a/automotive/vehicle/aidl/impl/grpc/GRPCVehicleHardware.cpp +++ b/automotive/vehicle/aidl/impl/grpc/GRPCVehicleHardware.cpp @@ -152,21 +152,49 @@ void GRPCVehicleHardware::registerOnPropertySetErrorEvent( mOnSetErr = std::move(callback); } -DumpResult GRPCVehicleHardware::dump(const std::vector& /* options */) { - // TODO(chenhaosjtuacm): To be implemented. - return {}; +DumpResult GRPCVehicleHardware::dump(const std::vector& options) { + ::grpc::ClientContext context; + proto::DumpOptions protoDumpOptions; + proto::DumpResult protoDumpResult; + for (const auto& option : options) { + protoDumpOptions.add_options(option); + } + auto grpc_status = mGrpcStub->Dump(&context, protoDumpOptions, &protoDumpResult); + if (!grpc_status.ok()) { + LOG(ERROR) << __func__ << ": GRPC Dump Failed: " << grpc_status.error_message(); + return {}; + } + return { + .callerShouldDumpState = protoDumpResult.caller_should_dump_state(), + .buffer = protoDumpResult.buffer(), + }; } aidlvhal::StatusCode GRPCVehicleHardware::checkHealth() { - // TODO(chenhaosjtuacm): To be implemented. - return aidlvhal::StatusCode::OK; + ::grpc::ClientContext context; + proto::VehicleHalCallStatus protoStatus; + auto grpc_status = mGrpcStub->CheckHealth(&context, ::google::protobuf::Empty(), &protoStatus); + if (!grpc_status.ok()) { + LOG(ERROR) << __func__ << ": GRPC CheckHealth Failed: " << grpc_status.error_message(); + return aidlvhal::StatusCode::INTERNAL_ERROR; + } + return static_cast(protoStatus.status_code()); } -aidlvhal::StatusCode GRPCVehicleHardware::updateSampleRate(int32_t /* propId */, - int32_t /* areaId */, - float /* sampleRate */) { - // TODO(chenhaosjtuacm): To be implemented. - return aidlvhal::StatusCode::OK; +aidlvhal::StatusCode GRPCVehicleHardware::updateSampleRate(int32_t propId, int32_t areaId, + float sampleRate) { + ::grpc::ClientContext context; + proto::UpdateSampleRateRequest request; + proto::VehicleHalCallStatus protoStatus; + request.set_prop(propId); + request.set_area_id(areaId); + request.set_sample_rate(sampleRate); + auto grpc_status = mGrpcStub->UpdateSampleRate(&context, request, &protoStatus); + if (!grpc_status.ok()) { + LOG(ERROR) << __func__ << ": GRPC UpdateSampleRate Failed: " << grpc_status.error_message(); + return aidlvhal::StatusCode::INTERNAL_ERROR; + } + return static_cast(protoStatus.status_code()); } bool GRPCVehicleHardware::waitForConnected(std::chrono::milliseconds waitTime) { diff --git a/automotive/vehicle/aidl/impl/grpc/GRPCVehicleProxyServer.cpp b/automotive/vehicle/aidl/impl/grpc/GRPCVehicleProxyServer.cpp index e2fe97b1c7..af3dd595a1 100644 --- a/automotive/vehicle/aidl/impl/grpc/GRPCVehicleProxyServer.cpp +++ b/automotive/vehicle/aidl/impl/grpc/GRPCVehicleProxyServer.cpp @@ -155,6 +155,33 @@ GrpcVehicleProxyServer::GrpcVehicleProxyServer(std::string serverAddr, return ::grpc::Status::OK; } +::grpc::Status GrpcVehicleProxyServer::UpdateSampleRate( + ::grpc::ServerContext* context, const proto::UpdateSampleRateRequest* request, + proto::VehicleHalCallStatus* status) { + const auto status_code = mHardware->updateSampleRate(request->prop(), request->area_id(), + request->sample_rate()); + status->set_status_code(static_cast(status_code)); + return ::grpc::Status::OK; +} + +::grpc::Status GrpcVehicleProxyServer::CheckHealth(::grpc::ServerContext* context, + const ::google::protobuf::Empty*, + proto::VehicleHalCallStatus* status) { + status->set_status_code(static_cast(mHardware->checkHealth())); + return ::grpc::Status::OK; +} + +::grpc::Status GrpcVehicleProxyServer::Dump(::grpc::ServerContext* context, + const proto::DumpOptions* options, + proto::DumpResult* result) { + std::vector dumpOptionStrings(options->options().begin(), + options->options().end()); + auto dumpResult = mHardware->dump(dumpOptionStrings); + result->set_caller_should_dump_state(dumpResult.callerShouldDumpState); + result->set_buffer(dumpResult.buffer); + return ::grpc::Status::OK; +} + ::grpc::Status GrpcVehicleProxyServer::StartPropertyValuesStream( ::grpc::ServerContext* context, const ::google::protobuf::Empty* request, ::grpc::ServerWriter* stream) { diff --git a/automotive/vehicle/aidl/impl/grpc/GRPCVehicleProxyServer.h b/automotive/vehicle/aidl/impl/grpc/GRPCVehicleProxyServer.h index 01beec3949..3596354539 100644 --- a/automotive/vehicle/aidl/impl/grpc/GRPCVehicleProxyServer.h +++ b/automotive/vehicle/aidl/impl/grpc/GRPCVehicleProxyServer.h @@ -53,6 +53,16 @@ class GrpcVehicleProxyServer : public proto::VehicleServer::Service { const proto::VehiclePropValueRequests* requests, proto::GetValueResults* results) override; + ::grpc::Status UpdateSampleRate(::grpc::ServerContext* context, + const proto::UpdateSampleRateRequest* request, + proto::VehicleHalCallStatus* status) override; + + ::grpc::Status CheckHealth(::grpc::ServerContext* context, const ::google::protobuf::Empty*, + proto::VehicleHalCallStatus* status) override; + + ::grpc::Status Dump(::grpc::ServerContext* context, const proto::DumpOptions* options, + proto::DumpResult* result) override; + ::grpc::Status StartPropertyValuesStream( ::grpc::ServerContext* context, const ::google::protobuf::Empty* request, ::grpc::ServerWriter* stream) override; diff --git a/automotive/vehicle/aidl/impl/grpc/proto/VehicleServer.proto b/automotive/vehicle/aidl/impl/grpc/proto/VehicleServer.proto index 349019595b..22b11d8c87 100644 --- a/automotive/vehicle/aidl/impl/grpc/proto/VehicleServer.proto +++ b/automotive/vehicle/aidl/impl/grpc/proto/VehicleServer.proto @@ -18,20 +18,14 @@ syntax = "proto3"; package android.hardware.automotive.vehicle.proto; +import "android/hardware/automotive/vehicle/DumpOptions.proto"; +import "android/hardware/automotive/vehicle/DumpResult.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) {} @@ -39,5 +33,11 @@ service VehicleServer { rpc GetValues(VehiclePropValueRequests) returns (GetValueResults) {} + rpc UpdateSampleRate(UpdateSampleRateRequest) returns (VehicleHalCallStatus) {} + + rpc CheckHealth(google.protobuf.Empty) returns (VehicleHalCallStatus) {} + + rpc Dump(DumpOptions) returns (DumpResult) {} + rpc StartPropertyValuesStream(google.protobuf.Empty) returns (stream VehiclePropValues) {} } diff --git a/automotive/vehicle/aidl/impl/proto/Android.bp b/automotive/vehicle/aidl/impl/proto/Android.bp index 709307d3e1..56fad7ed91 100644 --- a/automotive/vehicle/aidl/impl/proto/Android.bp +++ b/automotive/vehicle/aidl/impl/proto/Android.bp @@ -40,6 +40,7 @@ genrule { ":VehicleHalProtoFiles", ], out: [ + "android/hardware/automotive/vehicle/DumpOptions.pb.h", "android/hardware/automotive/vehicle/DumpResult.pb.h", "android/hardware/automotive/vehicle/StatusCode.pb.h", "android/hardware/automotive/vehicle/VehicleAreaConfig.pb.h", @@ -63,6 +64,7 @@ genrule { ":VehicleHalProtoFiles", ], out: [ + "android/hardware/automotive/vehicle/DumpOptions.pb.cc", "android/hardware/automotive/vehicle/DumpResult.pb.cc", "android/hardware/automotive/vehicle/StatusCode.pb.cc", "android/hardware/automotive/vehicle/VehicleAreaConfig.pb.cc", diff --git a/automotive/vehicle/aidl/impl/proto/android/hardware/automotive/vehicle/DumpOptions.proto b/automotive/vehicle/aidl/impl/proto/android/hardware/automotive/vehicle/DumpOptions.proto new file mode 100644 index 0000000000..4bed927288 --- /dev/null +++ b/automotive/vehicle/aidl/impl/proto/android/hardware/automotive/vehicle/DumpOptions.proto @@ -0,0 +1,23 @@ +/* + * 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; + +message DumpOptions { + repeated string options = 1; +} diff --git a/automotive/vehicle/aidl/impl/proto/android/hardware/automotive/vehicle/StatusCode.proto b/automotive/vehicle/aidl/impl/proto/android/hardware/automotive/vehicle/StatusCode.proto index 97cb0f88b2..63d7933e7d 100644 --- a/automotive/vehicle/aidl/impl/proto/android/hardware/automotive/vehicle/StatusCode.proto +++ b/automotive/vehicle/aidl/impl/proto/android/hardware/automotive/vehicle/StatusCode.proto @@ -39,3 +39,7 @@ enum StatusCode { /* Something unexpected has happened in Vehicle HAL */ INTERNAL_ERROR = 5; }; + +message VehicleHalCallStatus { + StatusCode status_code = 1; +} diff --git a/automotive/vehicle/aidl/impl/proto/android/hardware/automotive/vehicle/VehiclePropValue.proto b/automotive/vehicle/aidl/impl/proto/android/hardware/automotive/vehicle/VehiclePropValue.proto index 80c73cbb77..dda9ff5119 100644 --- a/automotive/vehicle/aidl/impl/proto/android/hardware/automotive/vehicle/VehiclePropValue.proto +++ b/automotive/vehicle/aidl/impl/proto/android/hardware/automotive/vehicle/VehiclePropValue.proto @@ -52,3 +52,7 @@ message VehiclePropValue { /* This is used for properties of type VehiclePropertyType#STRING */ string string_value = 9; }; + +message VehiclePropValues { + repeated VehiclePropValue values = 1; +} diff --git a/automotive/vehicle/aidl/impl/proto/android/hardware/automotive/vehicle/VehiclePropValueRequest.proto b/automotive/vehicle/aidl/impl/proto/android/hardware/automotive/vehicle/VehiclePropValueRequest.proto index 749ad6adc8..c347a800c3 100644 --- a/automotive/vehicle/aidl/impl/proto/android/hardware/automotive/vehicle/VehiclePropValueRequest.proto +++ b/automotive/vehicle/aidl/impl/proto/android/hardware/automotive/vehicle/VehiclePropValueRequest.proto @@ -26,6 +26,17 @@ message VehiclePropValueRequest { VehiclePropValue value = 2; }; +message UpdateSampleRateRequest { + /* Property identifier */ + int32 prop = 1; + + /* Area type(s) for non-global property it must be one of the value from + * VehicleArea* enums or 0 for global properties. */ + int32 area_id = 2; + + float sample_rate = 3; +}; + message SetValueResult { int64 request_id = 1; StatusCode status = 2;