Add subscribe to VHAL proto.

The latest IVehicleHardware adds Subscribe/Unsubscribe function
to replace the existing updateSampleRate. This CL adds the
Subscribe function to protobuf definition and implements it.

Test: atest GRPCVehicleHardwareUnitTest GRPCVehicleProxyServerUnitTest
Flag: EXEMPT hal change
Bug: 328316981
Merged-In: I4f02885b77f21a215a8b282be583f76118e400ba
(cherry-picked from commit: f1a869055fcd6ea980e329e86d71ace715427d30)

Change-Id: I4f02885b77f21a215a8b282be583f76118e400ba
diff --git a/automotive/vehicle/TEST_MAPPING b/automotive/vehicle/TEST_MAPPING
index e1a90cb..117c872 100644
--- a/automotive/vehicle/TEST_MAPPING
+++ b/automotive/vehicle/TEST_MAPPING
@@ -55,5 +55,10 @@
     {
       "name": "VehicleHalProtoMessageConverterTest"
     }
+  ],
+  "postsubmit": [
+    {
+      "name": "VehicleHalProtoMessageConverterTest"
+    }
   ]
 }
diff --git a/automotive/vehicle/aidl/impl/grpc/Android.bp b/automotive/vehicle/aidl/impl/grpc/Android.bp
index fd1d1ca..7a8da59 100644
--- a/automotive/vehicle/aidl/impl/grpc/Android.bp
+++ b/automotive/vehicle/aidl/impl/grpc/Android.bp
@@ -22,7 +22,7 @@
         "aprotoc",
         "protoc-gen-grpc-cpp-plugin",
     ],
-    cmd: "$(location aprotoc) -I$$(dirname $(location proto/VehicleServer.proto)) -Ihardware/interfaces/automotive/vehicle/aidl/impl/proto -Iexternal/protobuf/src --plugin=protoc-gen-grpc=$(location protoc-gen-grpc-cpp-plugin) $(location proto/VehicleServer.proto) --grpc_out=$(genDir) --cpp_out=$(genDir)",
+    cmd: "$(location aprotoc) -I$$(dirname $(location proto/VehicleServer.proto)) -Ihardware/interfaces/automotive/vehicle/aidl/impl/proto -Iexternal/protobuf/src --plugin=protoc-gen-grpc=$(location protoc-gen-grpc-cpp-plugin) $(location proto/VehicleServer.proto) --grpc_opt=generate_mock_code=true --grpc_out=$(genDir) --cpp_out=$(genDir)",
     srcs: [
         "proto/VehicleServer.proto",
         ":libprotobuf-internal-protos",
@@ -31,6 +31,7 @@
     out: [
         "VehicleServer.pb.h",
         "VehicleServer.grpc.pb.h",
+        "VehicleServer_mock.grpc.pb.h",
     ],
     visibility: ["//visibility:private"],
 }
diff --git a/automotive/vehicle/aidl/impl/grpc/GRPCVehicleHardware.cpp b/automotive/vehicle/aidl/impl/grpc/GRPCVehicleHardware.cpp
index 0742283..2e5d2e4 100644
--- a/automotive/vehicle/aidl/impl/grpc/GRPCVehicleHardware.cpp
+++ b/automotive/vehicle/aidl/impl/grpc/GRPCVehicleHardware.cpp
@@ -39,6 +39,13 @@
       mGrpcStub(proto::VehicleServer::NewStub(mGrpcChannel)),
       mValuePollingThread([this] { ValuePollingLoop(); }) {}
 
+// Only used for unit testing.
+GRPCVehicleHardware::GRPCVehicleHardware(std::unique_ptr<proto::VehicleServer::StubInterface> stub)
+    : mServiceAddr(""),
+      mGrpcChannel(nullptr),
+      mGrpcStub(std::move(stub)),
+      mValuePollingThread([] {}) {}
+
 GRPCVehicleHardware::~GRPCVehicleHardware() {
     {
         std::lock_guard lck(mShutdownMutex);
@@ -181,6 +188,24 @@
     return static_cast<aidlvhal::StatusCode>(protoStatus.status_code());
 }
 
+aidlvhal::StatusCode GRPCVehicleHardware::subscribe(aidlvhal::SubscribeOptions options) {
+    proto::SubscribeRequest request;
+    ::grpc::ClientContext context;
+    proto::VehicleHalCallStatus protoStatus;
+    proto_msg_converter::aidlToProto(options, request.mutable_options());
+    auto grpc_status = mGrpcStub->Subscribe(&context, request, &protoStatus);
+    if (!grpc_status.ok()) {
+        if (grpc_status.error_code() == ::grpc::StatusCode::UNIMPLEMENTED) {
+            // This is a legacy sever. It should handle updateSampleRate.
+            LOG(INFO) << __func__ << ": GRPC Subscribe is not supported by the server";
+            return aidlvhal::StatusCode::OK;
+        }
+        LOG(ERROR) << __func__ << ": GRPC Subscribe Failed: " << grpc_status.error_message();
+        return aidlvhal::StatusCode::INTERNAL_ERROR;
+    }
+    return static_cast<aidlvhal::StatusCode>(protoStatus.status_code());
+}
+
 aidlvhal::StatusCode GRPCVehicleHardware::updateSampleRate(int32_t propId, int32_t areaId,
                                                            float sampleRate) {
     ::grpc::ClientContext context;
diff --git a/automotive/vehicle/aidl/impl/grpc/GRPCVehicleHardware.h b/automotive/vehicle/aidl/impl/grpc/GRPCVehicleHardware.h
index ddd620e..bec957c 100644
--- a/automotive/vehicle/aidl/impl/grpc/GRPCVehicleHardware.h
+++ b/automotive/vehicle/aidl/impl/grpc/GRPCVehicleHardware.h
@@ -43,6 +43,9 @@
   public:
     explicit GRPCVehicleHardware(std::string service_addr);
 
+    // Only used for unit testing.
+    explicit GRPCVehicleHardware(std::unique_ptr<proto::VehicleServer::StubInterface> stub);
+
     ~GRPCVehicleHardware();
 
     // Get all the property configs.
@@ -80,6 +83,8 @@
     aidlvhal::StatusCode updateSampleRate(int32_t propId, int32_t areaId,
                                           float sampleRate) override;
 
+    aidlvhal::StatusCode subscribe(aidlvhal::SubscribeOptions options) override;
+
     bool waitForConnected(std::chrono::milliseconds waitTime);
 
   protected:
@@ -91,7 +96,7 @@
 
     std::string mServiceAddr;
     std::shared_ptr<::grpc::Channel> mGrpcChannel;
-    std::unique_ptr<proto::VehicleServer::Stub> mGrpcStub;
+    std::unique_ptr<proto::VehicleServer::StubInterface> mGrpcStub;
     std::thread mValuePollingThread;
 
     std::unique_ptr<const PropertySetErrorCallback> mOnSetErr;
diff --git a/automotive/vehicle/aidl/impl/grpc/GRPCVehicleProxyServer.cpp b/automotive/vehicle/aidl/impl/grpc/GRPCVehicleProxyServer.cpp
index af3dd59..558ab2f 100644
--- a/automotive/vehicle/aidl/impl/grpc/GRPCVehicleProxyServer.cpp
+++ b/automotive/vehicle/aidl/impl/grpc/GRPCVehicleProxyServer.cpp
@@ -164,6 +164,17 @@
     return ::grpc::Status::OK;
 }
 
+::grpc::Status GrpcVehicleProxyServer::Subscribe(::grpc::ServerContext* context,
+                                                 const proto::SubscribeRequest* request,
+                                                 proto::VehicleHalCallStatus* status) {
+    const auto& protoSubscribeOptions = request->options();
+    aidlvhal::SubscribeOptions aidlSubscribeOptions = {};
+    proto_msg_converter::protoToAidl(protoSubscribeOptions, &aidlSubscribeOptions);
+    const auto status_code = mHardware->subscribe(aidlSubscribeOptions);
+    status->set_status_code(static_cast<proto::StatusCode>(status_code));
+    return ::grpc::Status::OK;
+}
+
 ::grpc::Status GrpcVehicleProxyServer::CheckHealth(::grpc::ServerContext* context,
                                                    const ::google::protobuf::Empty*,
                                                    proto::VehicleHalCallStatus* status) {
diff --git a/automotive/vehicle/aidl/impl/grpc/GRPCVehicleProxyServer.h b/automotive/vehicle/aidl/impl/grpc/GRPCVehicleProxyServer.h
index 3596354..4f0c1e4 100644
--- a/automotive/vehicle/aidl/impl/grpc/GRPCVehicleProxyServer.h
+++ b/automotive/vehicle/aidl/impl/grpc/GRPCVehicleProxyServer.h
@@ -57,6 +57,9 @@
                                     const proto::UpdateSampleRateRequest* request,
                                     proto::VehicleHalCallStatus* status) override;
 
+    ::grpc::Status Subscribe(::grpc::ServerContext* context, const proto::SubscribeRequest* request,
+                             proto::VehicleHalCallStatus* status) override;
+
     ::grpc::Status CheckHealth(::grpc::ServerContext* context, const ::google::protobuf::Empty*,
                                proto::VehicleHalCallStatus* status) override;
 
diff --git a/automotive/vehicle/aidl/impl/grpc/proto/VehicleServer.proto b/automotive/vehicle/aidl/impl/grpc/proto/VehicleServer.proto
index 22b11d8..d4b5642 100644
--- a/automotive/vehicle/aidl/impl/grpc/proto/VehicleServer.proto
+++ b/automotive/vehicle/aidl/impl/grpc/proto/VehicleServer.proto
@@ -20,6 +20,7 @@
 
 import "android/hardware/automotive/vehicle/DumpOptions.proto";
 import "android/hardware/automotive/vehicle/DumpResult.proto";
+import "android/hardware/automotive/vehicle/SubscribeRequest.proto";
 import "android/hardware/automotive/vehicle/StatusCode.proto";
 import "android/hardware/automotive/vehicle/VehiclePropConfig.proto";
 import "android/hardware/automotive/vehicle/VehiclePropValue.proto";
@@ -40,4 +41,6 @@
     rpc Dump(DumpOptions) returns (DumpResult) {}
 
     rpc StartPropertyValuesStream(google.protobuf.Empty) returns (stream VehiclePropValues) {}
+
+    rpc Subscribe(SubscribeRequest) returns (VehicleHalCallStatus) {}
 }
diff --git a/automotive/vehicle/aidl/impl/grpc/test/GRPCVehicleHardwareUnitTest.cpp b/automotive/vehicle/aidl/impl/grpc/test/GRPCVehicleHardwareUnitTest.cpp
index f578021..24f078e 100644
--- a/automotive/vehicle/aidl/impl/grpc/test/GRPCVehicleHardwareUnitTest.cpp
+++ b/automotive/vehicle/aidl/impl/grpc/test/GRPCVehicleHardwareUnitTest.cpp
@@ -15,6 +15,7 @@
 #include "GRPCVehicleHardware.h"
 #include "VehicleServer.grpc.pb.h"
 #include "VehicleServer.pb.h"
+#include "VehicleServer_mock.grpc.pb.h"
 
 #include <gmock/gmock.h>
 #include <grpc++/grpc++.h>
@@ -26,6 +27,17 @@
 
 namespace android::hardware::automotive::vehicle::virtualization {
 
+namespace aidlvhal = ::aidl::android::hardware::automotive::vehicle;
+
+using ::testing::_;
+using ::testing::DoAll;
+using ::testing::NiceMock;
+using ::testing::Return;
+using ::testing::SaveArg;
+using ::testing::SetArgPointee;
+
+using proto::MockVehicleServerStub;
+
 const std::string kFakeServerAddr = "0.0.0.0:54321";
 
 class FakeVehicleServer : public proto::VehicleServer::Service {
@@ -91,4 +103,82 @@
     }
 }
 
+class GRPCVehicleHardwareMockServerUnitTest : public ::testing::Test {
+  protected:
+    NiceMock<MockVehicleServerStub>* mGrpcStub;
+    std::unique_ptr<GRPCVehicleHardware> mHardware;
+
+    void SetUp() override {
+        auto stub = std::make_unique<NiceMock<MockVehicleServerStub>>();
+        ;
+        mGrpcStub = stub.get();
+        mHardware = std::make_unique<GRPCVehicleHardware>(std::move(stub));
+    }
+
+    void TearDown() override { mHardware.reset(); }
+};
+
+MATCHER_P(RepeatedInt32Eq, expected_values, "") {
+    return std::vector<int32_t>(arg.begin(), arg.end()) == expected_values;
+}
+
+TEST_F(GRPCVehicleHardwareMockServerUnitTest, Subscribe) {
+    proto::VehicleHalCallStatus protoStatus;
+    protoStatus.set_status_code(proto::StatusCode::OK);
+    proto::SubscribeRequest actualRequest;
+
+    EXPECT_CALL(*mGrpcStub, Subscribe(_, _, _))
+            .WillOnce(DoAll(SaveArg<1>(&actualRequest), SetArgPointee<2>(protoStatus),
+                            Return(::grpc::Status::OK)));
+
+    aidlvhal::SubscribeOptions options = {.propId = 1,
+                                          .areaIds = {1, 2, 3, 4},
+                                          .sampleRate = 1.234,
+                                          .resolution = 0.01,
+                                          .enableVariableUpdateRate = true};
+    auto status = mHardware->subscribe(options);
+
+    EXPECT_EQ(status, aidlvhal::StatusCode::OK);
+    const auto& protoOptions = actualRequest.options();
+    EXPECT_EQ(protoOptions.prop_id(), 1);
+    EXPECT_THAT(protoOptions.area_ids(), RepeatedInt32Eq(std::vector<int32_t>({1, 2, 3, 4})));
+    EXPECT_FLOAT_EQ(protoOptions.sample_rate(), 1.234);
+    EXPECT_FLOAT_EQ(protoOptions.resolution(), 0.01);
+    EXPECT_EQ(protoOptions.enable_variable_update_rate(), true);
+}
+
+TEST_F(GRPCVehicleHardwareMockServerUnitTest, SubscribeLegacyServer) {
+    EXPECT_CALL(*mGrpcStub, Subscribe(_, _, _))
+            .WillOnce(Return(::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "")));
+
+    aidlvhal::SubscribeOptions options;  // Your options here (consider adding sample data)
+    auto status = mHardware->subscribe(options);
+
+    EXPECT_EQ(status, aidlvhal::StatusCode::OK);
+}
+
+TEST_F(GRPCVehicleHardwareMockServerUnitTest, SubscribeGrpcFailure) {
+    EXPECT_CALL(*mGrpcStub, Subscribe(_, _, _))
+            .WillOnce(Return(::grpc::Status(::grpc::StatusCode::INTERNAL, "GRPC Error")));
+
+    aidlvhal::SubscribeOptions options;
+    auto status = mHardware->subscribe(options);
+
+    EXPECT_EQ(status, aidlvhal::StatusCode::INTERNAL_ERROR);
+}
+
+TEST_F(GRPCVehicleHardwareMockServerUnitTest, SubscribeProtoFailure) {
+    proto::VehicleHalCallStatus protoStatus;
+    protoStatus.set_status_code(proto::StatusCode::NOT_AVAILABLE_SPEED_LOW);
+
+    EXPECT_CALL(*mGrpcStub, Subscribe(_, _, _))
+            .WillOnce(DoAll(SetArgPointee<2>(protoStatus),  // Set the output status
+                            Return(::grpc::Status::OK)));
+
+    aidlvhal::SubscribeOptions options;
+    auto status = mHardware->subscribe(options);
+
+    EXPECT_EQ(status, aidlvhal::StatusCode::NOT_AVAILABLE_SPEED_LOW);
+}
+
 }  // namespace android::hardware::automotive::vehicle::virtualization
diff --git a/automotive/vehicle/aidl/impl/grpc/test/GRPCVehicleProxyServerUnitTest.cpp b/automotive/vehicle/aidl/impl/grpc/test/GRPCVehicleProxyServerUnitTest.cpp
index 49e6fc9..61dabb9 100644
--- a/automotive/vehicle/aidl/impl/grpc/test/GRPCVehicleProxyServerUnitTest.cpp
+++ b/automotive/vehicle/aidl/impl/grpc/test/GRPCVehicleProxyServerUnitTest.cpp
@@ -30,6 +30,13 @@
 
 namespace android::hardware::automotive::vehicle::virtualization {
 
+namespace aidlvhal = ::aidl::android::hardware::automotive::vehicle;
+
+using ::testing::_;
+using ::testing::DoAll;
+using ::testing::Return;
+using ::testing::SaveArg;
+
 const std::string kFakeServerAddr = "0.0.0.0:54321";
 
 class VehicleHardwareForTest : public IVehicleHardware {
@@ -39,38 +46,30 @@
         mOnProp = std::move(callback);
     }
 
-    void onPropertyEvent(
-            std::vector<aidl::android::hardware::automotive::vehicle::VehiclePropValue> values) {
+    void onPropertyEvent(std::vector<aidlvhal::VehiclePropValue> values) {
         if (mOnProp) {
             (*mOnProp)(std::move(values));
         }
     }
 
     // Functions that we do not care.
-    std::vector<aidl::android::hardware::automotive::vehicle::VehiclePropConfig>
-    getAllPropertyConfigs() const override {
-        return {};
-    }
+    std::vector<aidlvhal::VehiclePropConfig> getAllPropertyConfigs() const override { return {}; }
 
-    aidl::android::hardware::automotive::vehicle::StatusCode setValues(
+    aidlvhal::StatusCode setValues(
             std::shared_ptr<const SetValuesCallback> callback,
-            const std::vector<aidl::android::hardware::automotive::vehicle::SetValueRequest>&
-                    requests) override {
-        return aidl::android::hardware::automotive::vehicle::StatusCode::OK;
+            const std::vector<aidlvhal::SetValueRequest>& requests) override {
+        return aidlvhal::StatusCode::OK;
     }
 
-    aidl::android::hardware::automotive::vehicle::StatusCode getValues(
+    aidlvhal::StatusCode getValues(
             std::shared_ptr<const GetValuesCallback> callback,
-            const std::vector<aidl::android::hardware::automotive::vehicle::GetValueRequest>&
-                    requests) const override {
-        return aidl::android::hardware::automotive::vehicle::StatusCode::OK;
+            const std::vector<aidlvhal::GetValueRequest>& requests) const override {
+        return aidlvhal::StatusCode::OK;
     }
 
     DumpResult dump(const std::vector<std::string>& options) override { return {}; }
 
-    aidl::android::hardware::automotive::vehicle::StatusCode checkHealth() override {
-        return aidl::android::hardware::automotive::vehicle::StatusCode::OK;
-    }
+    aidlvhal::StatusCode checkHealth() override { return aidlvhal::StatusCode::OK; }
 
     void registerOnPropertySetErrorEvent(
             std::unique_ptr<const PropertySetErrorCallback> callback) override {}
@@ -79,6 +78,35 @@
     std::unique_ptr<const PropertyChangeCallback> mOnProp;
 };
 
+class MockVehicleHardware : public IVehicleHardware {
+  public:
+    // Mock methods from IVehicleHardware
+    MOCK_METHOD(std::vector<aidlvhal::VehiclePropConfig>, getAllPropertyConfigs, (),
+                (const, override));
+
+    MOCK_METHOD((aidlvhal::StatusCode), setValues,
+                (std::shared_ptr<const SetValuesCallback> callback,
+                 const std::vector<aidlvhal::SetValueRequest>& requests),
+                (override));
+
+    MOCK_METHOD((aidlvhal::StatusCode), getValues,
+                (std::shared_ptr<const GetValuesCallback> callback,
+                 const std::vector<aidlvhal::GetValueRequest>& requests),
+                (const, override));
+
+    MOCK_METHOD(DumpResult, dump, (const std::vector<std::string>& options), (override));
+    MOCK_METHOD(aidlvhal::StatusCode, checkHealth, (), (override));
+    MOCK_METHOD(void, registerOnPropertyChangeEvent,
+                (std::unique_ptr<const PropertyChangeCallback> callback), (override));
+    MOCK_METHOD(void, registerOnPropertySetErrorEvent,
+                (std::unique_ptr<const PropertySetErrorCallback> callback), (override));
+    MOCK_METHOD(std::chrono::nanoseconds, getPropertyOnChangeEventBatchingWindow, (), (override));
+    MOCK_METHOD(aidlvhal::StatusCode, subscribe, (aidlvhal::SubscribeOptions options), (override));
+    MOCK_METHOD(aidlvhal::StatusCode, unsubscribe, (int32_t propId, int32_t areaId), (override));
+    MOCK_METHOD(aidlvhal::StatusCode, updateSampleRate,
+                (int32_t propId, int32_t areaId, float sampleRate), (override));
+};
+
 TEST(GRPCVehicleProxyServerUnitTest, ClientConnectDisconnect) {
     auto testHardware = std::make_unique<VehicleHardwareForTest>();
     // HACK: manipulate the underlying hardware via raw pointer for testing.
@@ -144,4 +172,51 @@
     vehicleServer->Shutdown().Wait();
 }
 
+TEST(GRPCVehicleProxyServerUnitTest, Subscribe) {
+    auto mockHardware = std::make_unique<MockVehicleHardware>();
+    // We make sure this is alive inside the function scope.
+    MockVehicleHardware* mockHardwarePtr = mockHardware.get();
+    GrpcVehicleProxyServer server = GrpcVehicleProxyServer("", std::move(mockHardware));
+    ::grpc::ServerContext context;
+    proto::SubscribeRequest request;
+    proto::VehicleHalCallStatus returnStatus;
+    aidlvhal::SubscribeOptions aidlOptions;
+    request.mutable_options()->set_prop_id(1);
+    request.mutable_options()->add_area_ids(2);
+    request.mutable_options()->set_sample_rate(1.234);
+    request.mutable_options()->set_resolution(0.01);
+    request.mutable_options()->set_enable_variable_update_rate(true);
+
+    EXPECT_CALL(*mockHardwarePtr, subscribe(_))
+            .WillOnce(DoAll(SaveArg<0>(&aidlOptions), Return(aidlvhal::StatusCode::OK)));
+
+    auto grpcStatus = server.Subscribe(&context, &request, &returnStatus);
+
+    EXPECT_TRUE(grpcStatus.ok());
+    EXPECT_EQ(returnStatus.status_code(), proto::StatusCode::OK);
+    EXPECT_EQ(aidlOptions.propId, 1);
+    EXPECT_EQ(aidlOptions.areaIds, std::vector<int32_t>{2});
+    EXPECT_FLOAT_EQ(aidlOptions.sampleRate, 1.234);
+    EXPECT_FLOAT_EQ(aidlOptions.resolution, 0.01);
+    EXPECT_TRUE(aidlOptions.enableVariableUpdateRate);
+}
+
+TEST(GRPCVehicleProxyServerUnitTest, SubscribeNotAvailable) {
+    auto mockHardware = std::make_unique<MockVehicleHardware>();
+    // We make sure this is alive inside the function scope.
+    MockVehicleHardware* mockHardwarePtr = mockHardware.get();
+    GrpcVehicleProxyServer server = GrpcVehicleProxyServer("", std::move(mockHardware));
+    ::grpc::ServerContext context;
+    proto::SubscribeRequest request;
+    proto::VehicleHalCallStatus returnStatus;
+
+    EXPECT_CALL(*mockHardwarePtr, subscribe(_))
+            .WillOnce(Return(aidlvhal::StatusCode::NOT_AVAILABLE));
+
+    auto grpcStatus = server.Subscribe(&context, &request, &returnStatus);
+
+    EXPECT_TRUE(grpcStatus.ok());
+    EXPECT_EQ(returnStatus.status_code(), proto::StatusCode::NOT_AVAILABLE);
+}
+
 }  // namespace android::hardware::automotive::vehicle::virtualization
diff --git a/automotive/vehicle/aidl/impl/grpc/utils/proto_message_converter/Android.bp b/automotive/vehicle/aidl/impl/grpc/utils/proto_message_converter/Android.bp
index d10aa3e..94c09aa 100644
--- a/automotive/vehicle/aidl/impl/grpc/utils/proto_message_converter/Android.bp
+++ b/automotive/vehicle/aidl/impl/grpc/utils/proto_message_converter/Android.bp
@@ -42,23 +42,21 @@
     host_supported: true,
 }
 
-cc_test {
+cc_test_host {
     name: "VehicleHalProtoMessageConverterTest",
     srcs: [
         "test/*.cpp",
     ],
     vendor: true,
     defaults: ["VehicleHalDefaults"],
-    shared_libs: [
-        "libprotobuf-cpp-full",
-        "libjsoncpp",
-    ],
     static_libs: [
         "VehicleHalJsonConfigLoaderEnableTestProperties",
         "VehicleHalProtoMessageConverter",
         "VehicleHalProtos",
         "VehicleHalUtils",
         "libgtest",
+        "libprotobuf-cpp-full",
+        "libjsoncpp",
     ],
     data: [
         ":VehicleHalDefaultProperties_JSON",
diff --git a/automotive/vehicle/aidl/impl/grpc/utils/proto_message_converter/include/ProtoMessageConverter.h b/automotive/vehicle/aidl/impl/grpc/utils/proto_message_converter/include/ProtoMessageConverter.h
index 1c26fe8..25c07ef 100644
--- a/automotive/vehicle/aidl/impl/grpc/utils/proto_message_converter/include/ProtoMessageConverter.h
+++ b/automotive/vehicle/aidl/impl/grpc/utils/proto_message_converter/include/ProtoMessageConverter.h
@@ -18,6 +18,7 @@
 #define android_hardware_automotive_vehicle_aidl_impl_grpc_utils_proto_message_converter_include_ProtoMessageConverter_H_
 
 #include <VehicleHalTypes.h>
+#include <android/hardware/automotive/vehicle/SubscribeOptions.pb.h>
 #include <android/hardware/automotive/vehicle/VehicleAreaConfig.pb.h>
 #include <android/hardware/automotive/vehicle/VehiclePropConfig.pb.h>
 #include <android/hardware/automotive/vehicle/VehiclePropValue.pb.h>
@@ -46,6 +47,12 @@
 void protoToAidl(
         const ::android::hardware::automotive::vehicle::proto::VehiclePropValue& inProtoVal,
         ::aidl::android::hardware::automotive::vehicle::VehiclePropValue* outAidlVal);
+// Convert AIDL SubscribeOptions to Protobuf SubscribeOptions.
+void aidlToProto(const ::aidl::android::hardware::automotive::vehicle::SubscribeOptions& in,
+                 ::android::hardware::automotive::vehicle::proto::SubscribeOptions* out);
+// Convert Protobuf SubscribeOptions to AIDL SubscribeOptions.
+void protoToAidl(const ::android::hardware::automotive::vehicle::proto::SubscribeOptions& in,
+                 ::aidl::android::hardware::automotive::vehicle::SubscribeOptions* out);
 
 }  // namespace proto_msg_converter
 }  // namespace vehicle
diff --git a/automotive/vehicle/aidl/impl/grpc/utils/proto_message_converter/src/ProtoMessageConverter.cpp b/automotive/vehicle/aidl/impl/grpc/utils/proto_message_converter/src/ProtoMessageConverter.cpp
index 1ea0df4..c40004a 100644
--- a/automotive/vehicle/aidl/impl/grpc/utils/proto_message_converter/src/ProtoMessageConverter.cpp
+++ b/automotive/vehicle/aidl/impl/grpc/utils/proto_message_converter/src/ProtoMessageConverter.cpp
@@ -152,6 +152,24 @@
     COPY_PROTOBUF_VEC_TO_VHAL_TYPE(in, float_values, out, value.floatValues);
 }
 
+void aidlToProto(const aidl_vehicle::SubscribeOptions& in, proto::SubscribeOptions* out) {
+    out->set_prop_id(in.propId);
+    for (int areaId : in.areaIds) {
+        out->add_area_ids(areaId);
+    }
+    out->set_sample_rate(in.sampleRate);
+    out->set_resolution(in.resolution);
+    out->set_enable_variable_update_rate(in.enableVariableUpdateRate);
+}
+
+void protoToAidl(const proto::SubscribeOptions& in, aidl_vehicle::SubscribeOptions* out) {
+    out->propId = in.prop_id();
+    COPY_PROTOBUF_VEC_TO_VHAL_TYPE(in, area_ids, out, areaIds);
+    out->sampleRate = in.sample_rate();
+    out->resolution = in.resolution();
+    out->enableVariableUpdateRate = in.enable_variable_update_rate();
+}
+
 #undef COPY_PROTOBUF_VEC_TO_VHAL_TYPE
 #undef CAST_COPY_PROTOBUF_VEC_TO_VHAL_TYPE
 
diff --git a/automotive/vehicle/aidl/impl/grpc/utils/proto_message_converter/test/proto_message_converter_test.cpp b/automotive/vehicle/aidl/impl/grpc/utils/proto_message_converter/test/proto_message_converter_test.cpp
index 308be46..2efda5b 100644
--- a/automotive/vehicle/aidl/impl/grpc/utils/proto_message_converter/test/proto_message_converter_test.cpp
+++ b/automotive/vehicle/aidl/impl/grpc/utils/proto_message_converter/test/proto_message_converter_test.cpp
@@ -22,6 +22,7 @@
 
 #include <android-base/file.h>
 #include <android-base/format.h>
+#include <android/hardware/automotive/vehicle/SubscribeOptions.pb.h>
 #include <android/hardware/automotive/vehicle/VehiclePropConfig.pb.h>
 #include <android/hardware/automotive/vehicle/VehiclePropValue.pb.h>
 #include <gtest/gtest.h>
@@ -114,6 +115,21 @@
                              return ::fmt::format("property_{:d}", info.param.prop);
                          });
 
+TEST_F(PropValueConversionTest, testConvertSubscribeOption) {
+    proto::SubscribeOptions protoOptions;
+    aidl_vehicle::SubscribeOptions aidlOptions = {.propId = 1,
+                                                  .areaIds = {1, 2},
+                                                  .sampleRate = 1.234,
+                                                  .resolution = 0.01,
+                                                  .enableVariableUpdateRate = true};
+    aidl_vehicle::SubscribeOptions outputOptions;
+
+    aidlToProto(aidlOptions, &protoOptions);
+    protoToAidl(protoOptions, &outputOptions);
+
+    EXPECT_EQ(aidlOptions, outputOptions);
+}
+
 }  // namespace proto_msg_converter
 }  // namespace vehicle
 }  // namespace automotive
diff --git a/automotive/vehicle/aidl/impl/proto/Android.bp b/automotive/vehicle/aidl/impl/proto/Android.bp
index 56fad7e..c636bb9 100644
--- a/automotive/vehicle/aidl/impl/proto/Android.bp
+++ b/automotive/vehicle/aidl/impl/proto/Android.bp
@@ -50,6 +50,8 @@
         "android/hardware/automotive/vehicle/VehiclePropertyStatus.pb.h",
         "android/hardware/automotive/vehicle/VehiclePropValue.pb.h",
         "android/hardware/automotive/vehicle/VehiclePropValueRequest.pb.h",
+        "android/hardware/automotive/vehicle/SubscribeOptions.pb.h",
+        "android/hardware/automotive/vehicle/SubscribeRequest.pb.h",
     ],
 }
 
@@ -74,6 +76,8 @@
         "android/hardware/automotive/vehicle/VehiclePropertyStatus.pb.cc",
         "android/hardware/automotive/vehicle/VehiclePropValue.pb.cc",
         "android/hardware/automotive/vehicle/VehiclePropValueRequest.pb.cc",
+        "android/hardware/automotive/vehicle/SubscribeOptions.pb.cc",
+        "android/hardware/automotive/vehicle/SubscribeRequest.pb.cc",
     ],
 }
 
diff --git a/automotive/vehicle/aidl/impl/proto/android/hardware/automotive/vehicle/SubscribeOptions.proto b/automotive/vehicle/aidl/impl/proto/android/hardware/automotive/vehicle/SubscribeOptions.proto
new file mode 100644
index 0000000..3fc6581
--- /dev/null
+++ b/automotive/vehicle/aidl/impl/proto/android/hardware/automotive/vehicle/SubscribeOptions.proto
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2024 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 SubscribeOptions {
+    int32 prop_id = 1;
+    repeated int32 area_ids = 2;
+    float sample_rate = 3;
+    float resolution = 4;
+    bool enable_variable_update_rate = 5;
+}
\ No newline at end of file
diff --git a/automotive/vehicle/aidl/impl/proto/android/hardware/automotive/vehicle/SubscribeRequest.proto b/automotive/vehicle/aidl/impl/proto/android/hardware/automotive/vehicle/SubscribeRequest.proto
new file mode 100644
index 0000000..4ce6335
--- /dev/null
+++ b/automotive/vehicle/aidl/impl/proto/android/hardware/automotive/vehicle/SubscribeRequest.proto
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2024 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/SubscribeOptions.proto";
+
+message SubscribeRequest {
+    SubscribeOptions options = 1;
+}
\ No newline at end of file