Merge "Replacing manual CBOR description with CDDL." into main
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/Android.bp b/automotive/vehicle/aidl/Android.bp
index 5ca1fc8..ff0635a 100644
--- a/automotive/vehicle/aidl/Android.bp
+++ b/automotive/vehicle/aidl/Android.bp
@@ -56,5 +56,5 @@
},
],
-
+ host_supported: true,
}
diff --git a/automotive/vehicle/aidl/generated_lib/cpp/Android.bp b/automotive/vehicle/aidl/generated_lib/cpp/Android.bp
index 11d3693..d14cbc2 100644
--- a/automotive/vehicle/aidl/generated_lib/cpp/Android.bp
+++ b/automotive/vehicle/aidl/generated_lib/cpp/Android.bp
@@ -24,4 +24,5 @@
local_include_dirs: ["."],
export_include_dirs: ["."],
defaults: ["VehicleHalInterfaceDefaults"],
+ host_supported: true,
}
diff --git a/automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/Android.bp b/automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/Android.bp
index 75a3541..d1974ac 100644
--- a/automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/Android.bp
+++ b/automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/Android.bp
@@ -49,6 +49,7 @@
],
cflags: ["-DENABLE_VEHICLE_HAL_TEST_PROPERTIES"],
shared_libs: ["libjsoncpp"],
+ host_supported: true,
}
cc_library_headers {
diff --git a/automotive/vehicle/aidl/impl/default_config/config/Android.bp b/automotive/vehicle/aidl/impl/default_config/config/Android.bp
index 8f1c7d1..c4f93c4 100644
--- a/automotive/vehicle/aidl/impl/default_config/config/Android.bp
+++ b/automotive/vehicle/aidl/impl/default_config/config/Android.bp
@@ -45,3 +45,24 @@
sub_dir: "automotive/vhalconfig/",
vendor: true,
}
+
+prebuilt_etc_host {
+ name: "Host_Prebuilt_VehicleHalDefaultProperties_JSON",
+ filename_from_src: true,
+ src: "DefaultProperties.json",
+ relative_install_path: "automotive/vhalconfig/",
+}
+
+prebuilt_etc_host {
+ name: "Host_Prebuilt_VehicleHalTestProperties_JSON",
+ filename_from_src: true,
+ src: "TestProperties.json",
+ relative_install_path: "automotive/vhalconfig/",
+}
+
+prebuilt_etc_host {
+ name: "Host_Prebuilt_VehicleHalVendorClusterTestProperties_JSON",
+ filename_from_src: true,
+ src: "VendorClusterTestProperties.json",
+ relative_install_path: "automotive/vhalconfig/",
+}
diff --git a/automotive/vehicle/aidl/impl/fake_impl/GeneratorHub/Android.bp b/automotive/vehicle/aidl/impl/fake_impl/GeneratorHub/Android.bp
index ab223d3..a250a47 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/GeneratorHub/Android.bp
+++ b/automotive/vehicle/aidl/impl/fake_impl/GeneratorHub/Android.bp
@@ -32,4 +32,5 @@
shared_libs: [
"libjsoncpp",
],
+ host_supported: true,
}
diff --git a/automotive/vehicle/aidl/impl/fake_impl/hardware/Android.bp b/automotive/vehicle/aidl/impl/fake_impl/hardware/Android.bp
index e75f648..33b403f 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/hardware/Android.bp
+++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/Android.bp
@@ -32,6 +32,7 @@
"VehicleHalDefaults",
"FakeVehicleHardwareDefaults",
],
+ host_supported: true,
}
cc_defaults {
diff --git a/automotive/vehicle/aidl/impl/fake_impl/hardware/include/FakeVehicleHardware.h b/automotive/vehicle/aidl/impl/fake_impl/hardware/include/FakeVehicleHardware.h
index d986b41..1b6f576 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/hardware/include/FakeVehicleHardware.h
+++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/include/FakeVehicleHardware.h
@@ -200,7 +200,7 @@
EXCLUDES(mLock);
// Load the config files in format '*.json' from the directory and parse the config files
// into a map from property ID to ConfigDeclarations.
- void loadPropConfigsFromDir(const std::string& dirPath,
+ bool loadPropConfigsFromDir(const std::string& dirPath,
std::unordered_map<int32_t, ConfigDeclaration>* configs);
// Function to be called when a value change event comes from vehicle bus. In our fake
// implementation, this function is only called during "--inject-event" dump command.
diff --git a/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp b/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp
index dced624..2b20f38 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp
+++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp
@@ -329,7 +329,12 @@
std::unordered_map<int32_t, ConfigDeclaration> FakeVehicleHardware::loadConfigDeclarations() {
std::unordered_map<int32_t, ConfigDeclaration> configsByPropId;
- loadPropConfigsFromDir(mDefaultConfigDir, &configsByPropId);
+ bool defaultConfigLoaded = loadPropConfigsFromDir(mDefaultConfigDir, &configsByPropId);
+ if (!defaultConfigLoaded) {
+ // This cannot work without a valid default config.
+ ALOGE("Failed to load default config, exiting");
+ exit(1);
+ }
if (UseOverrideConfigDir()) {
loadPropConfigsFromDir(mOverrideConfigDir, &configsByPropId);
}
@@ -2258,30 +2263,35 @@
(*mOnPropertyChangeCallback)(std::move(subscribedUpdatedValues));
}
-void FakeVehicleHardware::loadPropConfigsFromDir(
+bool FakeVehicleHardware::loadPropConfigsFromDir(
const std::string& dirPath,
std::unordered_map<int32_t, ConfigDeclaration>* configsByPropId) {
ALOGI("loading properties from %s", dirPath.c_str());
- if (auto dir = opendir(dirPath.c_str()); dir != NULL) {
- std::regex regJson(".*[.]json", std::regex::icase);
- while (auto f = readdir(dir)) {
- if (!std::regex_match(f->d_name, regJson)) {
- continue;
- }
- std::string filePath = dirPath + "/" + std::string(f->d_name);
- ALOGI("loading properties from %s", filePath.c_str());
- auto result = mLoader.loadPropConfig(filePath);
- if (!result.ok()) {
- ALOGE("failed to load config file: %s, error: %s", filePath.c_str(),
- result.error().message().c_str());
- continue;
- }
- for (auto& [propId, configDeclaration] : result.value()) {
- (*configsByPropId)[propId] = std::move(configDeclaration);
- }
- }
- closedir(dir);
+ auto dir = opendir(dirPath.c_str());
+ if (dir == nullptr) {
+ ALOGE("Failed to open config directory: %s", dirPath.c_str());
+ return false;
}
+
+ std::regex regJson(".*[.]json", std::regex::icase);
+ while (auto f = readdir(dir)) {
+ if (!std::regex_match(f->d_name, regJson)) {
+ continue;
+ }
+ std::string filePath = dirPath + "/" + std::string(f->d_name);
+ ALOGI("loading properties from %s", filePath.c_str());
+ auto result = mLoader.loadPropConfig(filePath);
+ if (!result.ok()) {
+ ALOGE("failed to load config file: %s, error: %s", filePath.c_str(),
+ result.error().message().c_str());
+ continue;
+ }
+ for (auto& [propId, configDeclaration] : result.value()) {
+ (*configsByPropId)[propId] = std::move(configDeclaration);
+ }
+ }
+ closedir(dir);
+ return true;
}
Result<float> FakeVehicleHardware::safelyParseFloat(int index, const std::string& s) {
diff --git a/automotive/vehicle/aidl/impl/fake_impl/hardware/test/Android.bp b/automotive/vehicle/aidl/impl/fake_impl/hardware/test/Android.bp
index 9819f3c..a335eea 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/hardware/test/Android.bp
+++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/test/Android.bp
@@ -54,6 +54,8 @@
defaults: [
"VehicleHalDefaults",
],
+ // Need root to use vendor lib: libgrpc++.
+ require_root: true,
test_suites: ["device-tests"],
}
diff --git a/automotive/vehicle/aidl/impl/fake_impl/obd2frame/Android.bp b/automotive/vehicle/aidl/impl/fake_impl/obd2frame/Android.bp
index c1cee84..8fc7341 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/obd2frame/Android.bp
+++ b/automotive/vehicle/aidl/impl/fake_impl/obd2frame/Android.bp
@@ -29,4 +29,5 @@
"VehicleHalUtils",
],
export_static_lib_headers: ["VehicleHalUtils"],
+ host_supported: true,
}
diff --git a/automotive/vehicle/aidl/impl/fake_impl/userhal/Android.bp b/automotive/vehicle/aidl/impl/fake_impl/userhal/Android.bp
index 2e95531..181fd10 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/userhal/Android.bp
+++ b/automotive/vehicle/aidl/impl/fake_impl/userhal/Android.bp
@@ -29,4 +29,5 @@
"VehicleHalUtils",
],
export_static_lib_headers: ["VehicleHalUtils"],
+ host_supported: true,
}
diff --git a/automotive/vehicle/aidl/impl/grpc/Android.bp b/automotive/vehicle/aidl/impl/grpc/Android.bp
index e5106f8..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"],
}
@@ -127,4 +128,5 @@
cflags: [
"-Wno-unused-parameter",
],
+ host_supported: true,
}
diff --git a/automotive/vehicle/aidl/impl/grpc/GRPCVehicleHardware.cpp b/automotive/vehicle/aidl/impl/grpc/GRPCVehicleHardware.cpp
index 0742283..f44573a 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,43 @@
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::unsubscribe(int32_t propId, int32_t areaId) {
+ proto::UnsubscribeRequest request;
+ ::grpc::ClientContext context;
+ proto::VehicleHalCallStatus protoStatus;
+ request.set_prop_id(propId);
+ request.set_area_id(areaId);
+ auto grpc_status = mGrpcStub->Unsubscribe(&context, request, &protoStatus);
+ if (!grpc_status.ok()) {
+ if (grpc_status.error_code() == ::grpc::StatusCode::UNIMPLEMENTED) {
+ // This is a legacy sever. Ignore unsubscribe request.
+ LOG(INFO) << __func__ << ": GRPC Unsubscribe is not supported by the server";
+ return aidlvhal::StatusCode::OK;
+ }
+ LOG(ERROR) << __func__ << ": GRPC Unsubscribe 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..9750f62 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,10 @@
aidlvhal::StatusCode updateSampleRate(int32_t propId, int32_t areaId,
float sampleRate) override;
+ aidlvhal::StatusCode subscribe(aidlvhal::SubscribeOptions options) override;
+
+ aidlvhal::StatusCode unsubscribe(int32_t propId, int32_t areaId) override;
+
bool waitForConnected(std::chrono::milliseconds waitTime);
protected:
@@ -91,7 +98,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..a6abfa3 100644
--- a/automotive/vehicle/aidl/impl/grpc/GRPCVehicleProxyServer.cpp
+++ b/automotive/vehicle/aidl/impl/grpc/GRPCVehicleProxyServer.cpp
@@ -164,6 +164,27 @@
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::Unsubscribe(::grpc::ServerContext* context,
+ const proto::UnsubscribeRequest* request,
+ proto::VehicleHalCallStatus* status) {
+ int32_t propId = request->prop_id();
+ int32_t areaId = request->area_id();
+ const auto status_code = mHardware->unsubscribe(propId, areaId);
+ 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..dd9e2aa 100644
--- a/automotive/vehicle/aidl/impl/grpc/GRPCVehicleProxyServer.h
+++ b/automotive/vehicle/aidl/impl/grpc/GRPCVehicleProxyServer.h
@@ -57,6 +57,13 @@
const proto::UpdateSampleRateRequest* request,
proto::VehicleHalCallStatus* status) override;
+ ::grpc::Status Subscribe(::grpc::ServerContext* context, const proto::SubscribeRequest* request,
+ proto::VehicleHalCallStatus* status) override;
+
+ ::grpc::Status Unsubscribe(::grpc::ServerContext* context,
+ const proto::UnsubscribeRequest* 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..732957f 100644
--- a/automotive/vehicle/aidl/impl/grpc/proto/VehicleServer.proto
+++ b/automotive/vehicle/aidl/impl/grpc/proto/VehicleServer.proto
@@ -20,7 +20,9 @@
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/UnsubscribeRequest.proto";
import "android/hardware/automotive/vehicle/VehiclePropConfig.proto";
import "android/hardware/automotive/vehicle/VehiclePropValue.proto";
import "android/hardware/automotive/vehicle/VehiclePropValueRequest.proto";
@@ -40,4 +42,8 @@
rpc Dump(DumpOptions) returns (DumpResult) {}
rpc StartPropertyValuesStream(google.protobuf.Empty) returns (stream VehiclePropValues) {}
+
+ rpc Subscribe(SubscribeRequest) returns (VehicleHalCallStatus) {}
+
+ rpc Unsubscribe(UnsubscribeRequest) returns (VehicleHalCallStatus) {}
}
diff --git a/automotive/vehicle/aidl/impl/grpc/test/GRPCVehicleHardwareUnitTest.cpp b/automotive/vehicle/aidl/impl/grpc/test/GRPCVehicleHardwareUnitTest.cpp
index f578021..3bd7e0e 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,131 @@
}
}
+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;
+ 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);
+}
+
+TEST_F(GRPCVehicleHardwareMockServerUnitTest, Unsubscribe) {
+ proto::VehicleHalCallStatus protoStatus;
+ protoStatus.set_status_code(proto::StatusCode::OK);
+ proto::UnsubscribeRequest actualRequest;
+
+ EXPECT_CALL(*mGrpcStub, Unsubscribe(_, _, _))
+ .WillOnce(DoAll(SaveArg<1>(&actualRequest), SetArgPointee<2>(protoStatus),
+ Return(::grpc::Status::OK)));
+
+ int32_t propId = 1;
+ int32_t areaId = 2;
+ auto status = mHardware->unsubscribe(propId, areaId);
+
+ EXPECT_EQ(status, aidlvhal::StatusCode::OK);
+ EXPECT_EQ(actualRequest.prop_id(), propId);
+ EXPECT_EQ(actualRequest.area_id(), areaId);
+}
+
+TEST_F(GRPCVehicleHardwareMockServerUnitTest, UnsubscribeLegacyServer) {
+ EXPECT_CALL(*mGrpcStub, Unsubscribe(_, _, _))
+ .WillOnce(Return(::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "")));
+
+ auto status = mHardware->unsubscribe(1, 2);
+
+ EXPECT_EQ(status, aidlvhal::StatusCode::OK);
+}
+
+TEST_F(GRPCVehicleHardwareMockServerUnitTest, UnsubscribeGrpcFailure) {
+ EXPECT_CALL(*mGrpcStub, Unsubscribe(_, _, _))
+ .WillOnce(Return(::grpc::Status(::grpc::StatusCode::INTERNAL, "GRPC Error")));
+
+ auto status = mHardware->unsubscribe(1, 2);
+
+ EXPECT_EQ(status, aidlvhal::StatusCode::INTERNAL_ERROR);
+}
+
+TEST_F(GRPCVehicleHardwareMockServerUnitTest, UnsubscribeProtoFailure) {
+ proto::VehicleHalCallStatus protoStatus;
+ protoStatus.set_status_code(proto::StatusCode::NOT_AVAILABLE_SPEED_LOW);
+
+ EXPECT_CALL(*mGrpcStub, Unsubscribe(_, _, _))
+ .WillOnce(DoAll(SetArgPointee<2>(protoStatus), // Set the output status
+ Return(::grpc::Status::OK)));
+
+ auto status = mHardware->unsubscribe(1, 2);
+
+ 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..ca5c2d5 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,70 @@
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);
+}
+
+TEST(GRPCVehicleProxyServerUnitTest, Unsubscribe) {
+ 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::UnsubscribeRequest request;
+ proto::VehicleHalCallStatus returnStatus;
+ request.set_prop_id(1);
+ request.set_area_id(2);
+
+ EXPECT_CALL(*mockHardwarePtr, unsubscribe(1, 2)).WillOnce(Return(aidlvhal::StatusCode::OK));
+
+ auto grpcStatus = server.Unsubscribe(&context, &request, &returnStatus);
+
+ EXPECT_TRUE(grpcStatus.ok());
+ EXPECT_EQ(returnStatus.status_code(), proto::StatusCode::OK);
+}
+
} // 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 52ef7be..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
@@ -39,25 +39,24 @@
],
defaults: ["VehicleHalDefaults"],
export_static_lib_headers: ["VehicleHalUtils"],
+ 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/hardware/Android.bp b/automotive/vehicle/aidl/impl/hardware/Android.bp
index edb0f29..52fd5e4 100644
--- a/automotive/vehicle/aidl/impl/hardware/Android.bp
+++ b/automotive/vehicle/aidl/impl/hardware/Android.bp
@@ -30,4 +30,5 @@
export_header_lib_headers: [
"VehicleHalUtilHeaders",
],
+ host_supported: true,
}
diff --git a/automotive/vehicle/aidl/impl/proto/Android.bp b/automotive/vehicle/aidl/impl/proto/Android.bp
index 56fad7e..b2edf75 100644
--- a/automotive/vehicle/aidl/impl/proto/Android.bp
+++ b/automotive/vehicle/aidl/impl/proto/Android.bp
@@ -50,6 +50,9 @@
"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",
+ "android/hardware/automotive/vehicle/UnsubscribeRequest.pb.h",
],
}
@@ -74,6 +77,9 @@
"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",
+ "android/hardware/automotive/vehicle/UnsubscribeRequest.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
diff --git a/automotive/vehicle/aidl/impl/proto/android/hardware/automotive/vehicle/UnsubscribeRequest.proto b/automotive/vehicle/aidl/impl/proto/android/hardware/automotive/vehicle/UnsubscribeRequest.proto
new file mode 100644
index 0000000..314fbf0
--- /dev/null
+++ b/automotive/vehicle/aidl/impl/proto/android/hardware/automotive/vehicle/UnsubscribeRequest.proto
@@ -0,0 +1,24 @@
+/*
+ * 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 UnsubscribeRequest {
+ int32 prop_id = 1;
+ int32 area_id = 2;
+}
\ No newline at end of file
diff --git a/automotive/vehicle/aidl/impl/utils/common/Android.bp b/automotive/vehicle/aidl/impl/utils/common/Android.bp
index e5d9346..5cd07b4 100644
--- a/automotive/vehicle/aidl/impl/utils/common/Android.bp
+++ b/automotive/vehicle/aidl/impl/utils/common/Android.bp
@@ -25,10 +25,12 @@
local_include_dirs: ["include"],
export_include_dirs: ["include"],
defaults: ["VehicleHalDefaults"],
+ host_supported: true,
}
cc_library_headers {
name: "VehicleHalUtilHeaders",
export_include_dirs: ["include"],
vendor: true,
+ host_supported: true,
}
diff --git a/automotive/vehicle/aidl/impl/utils/common/src/VehiclePropertyStore.cpp b/automotive/vehicle/aidl/impl/utils/common/src/VehiclePropertyStore.cpp
index 6a2a695..3d0a524 100644
--- a/automotive/vehicle/aidl/impl/utils/common/src/VehiclePropertyStore.cpp
+++ b/automotive/vehicle/aidl/impl/utils/common/src/VehiclePropertyStore.cpp
@@ -173,9 +173,7 @@
}
if (onValuesChangeCallback == nullptr && onValueChangeCallback == nullptr) {
- ALOGW("No callback registered, ignoring property update for propId: %" PRId32
- ", area ID: %" PRId32,
- propId, areaId);
+ // No callback registered.
return {};
}
diff --git a/automotive/vehicle/aidl_property/Android.bp b/automotive/vehicle/aidl_property/Android.bp
index 5db39d8..6a49792 100644
--- a/automotive/vehicle/aidl_property/Android.bp
+++ b/automotive/vehicle/aidl_property/Android.bp
@@ -56,6 +56,7 @@
imports: [],
},
],
+ host_supported: true,
}
filegroup {
diff --git a/bluetooth/audio/flags/btaudiohal.aconfig b/bluetooth/audio/flags/btaudiohal.aconfig
index 4c1500a..13e2116 100644
--- a/bluetooth/audio/flags/btaudiohal.aconfig
+++ b/bluetooth/audio/flags/btaudiohal.aconfig
@@ -7,3 +7,10 @@
description: "Flag for DSA Over LEA"
bug: "270987427"
}
+
+flag {
+ name: "leaudio_report_broadcast_ac_to_hal"
+ namespace: "pixel_bluetooth"
+ description: "Flag for reporting lea broadcast audio config to HAL"
+ bug: "321168976"
+}
\ No newline at end of file
diff --git a/bluetooth/audio/utils/aidl_session/BluetoothAudioSession.cpp b/bluetooth/audio/utils/aidl_session/BluetoothAudioSession.cpp
index 67ba93c..d0f2a26 100644
--- a/bluetooth/audio/utils/aidl_session/BluetoothAudioSession.cpp
+++ b/bluetooth/audio/utils/aidl_session/BluetoothAudioSession.cpp
@@ -121,18 +121,41 @@
void BluetoothAudioSession::ReportAudioConfigChanged(
const AudioConfiguration& audio_config) {
- if (session_type_ !=
- SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH &&
- session_type_ !=
- SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH) {
- return;
- }
-
std::lock_guard<std::recursive_mutex> guard(mutex_);
- if (audio_config.getTag() != AudioConfiguration::leAudioConfig) {
- LOG(ERROR) << __func__ << " invalid audio config type for SessionType ="
- << toString(session_type_);
- return;
+ if (com::android::btaudio::hal::flags::leaudio_report_broadcast_ac_to_hal()) {
+ if (session_type_ ==
+ SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH ||
+ session_type_ ==
+ SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH) {
+ if (audio_config.getTag() != AudioConfiguration::leAudioConfig) {
+ LOG(ERROR) << __func__ << " invalid audio config type for SessionType ="
+ << toString(session_type_);
+ return;
+ }
+ } else if (session_type_ ==
+ SessionType::LE_AUDIO_BROADCAST_HARDWARE_OFFLOAD_ENCODING_DATAPATH) {
+ if (audio_config.getTag() != AudioConfiguration::leAudioBroadcastConfig) {
+ LOG(ERROR) << __func__ << " invalid audio config type for SessionType ="
+ << toString(session_type_);
+ return;
+ }
+ } else {
+ LOG(ERROR) << __func__ << " invalid SessionType ="
+ << toString(session_type_);
+ return;
+ }
+ } else {
+ if (session_type_ !=
+ SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH &&
+ session_type_ !=
+ SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH) {
+ return;
+ }
+ if (audio_config.getTag() != AudioConfiguration::leAudioConfig) {
+ LOG(ERROR) << __func__ << " invalid audio config type for SessionType ="
+ << toString(session_type_);
+ return;
+ }
}
audio_config_ = std::make_unique<AudioConfiguration>(audio_config);
diff --git a/security/keymint/support/fuzzer/Android.bp b/security/keymint/support/fuzzer/Android.bp
new file mode 100644
index 0000000..1b1a580
--- /dev/null
+++ b/security/keymint/support/fuzzer/Android.bp
@@ -0,0 +1,69 @@
+/*
+ * 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.
+ *
+ */
+
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "hardware_interfaces_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["hardware_interfaces_license"],
+ default_team: "trendy_team_android_hardware_backed_security",
+}
+
+cc_defaults {
+ name: "keymint_fuzzer_defaults",
+ static_libs: [
+ "libhidlbase",
+ "libkeymint_support",
+ ],
+ shared_libs: [
+ "libbase",
+ "libcrypto",
+ "libutils",
+ "libhardware",
+ "libbinder_ndk",
+ "liblog",
+ ],
+ defaults: [
+ "keymint_use_latest_hal_aidl_ndk_shared",
+ ],
+ include_dirs: [
+ "hardware/interfaces/security/keymint/support/include",
+ "frameworks/native/libs/binder/ndk/include_platform",
+ ],
+}
+
+cc_fuzz {
+ name: "keymint_attestation_fuzzer",
+ srcs: [
+ "keymint_attestation_fuzzer.cpp",
+ ],
+ defaults: [
+ "keymint_fuzzer_defaults",
+ ],
+}
+
+cc_fuzz {
+ name: "keymint_authSet_fuzzer",
+ srcs: [
+ "keymint_authSet_fuzzer.cpp",
+ ],
+ defaults: [
+ "keymint_fuzzer_defaults",
+ ],
+}
diff --git a/security/keymint/support/fuzzer/README.md b/security/keymint/support/fuzzer/README.md
new file mode 100644
index 0000000..d41af08
--- /dev/null
+++ b/security/keymint/support/fuzzer/README.md
@@ -0,0 +1,79 @@
+# Fuzzers for libkeymint_support
+
+## Plugin Design Considerations
+The fuzzer plugins for libkeymint_support are designed based on the understanding of the source code and try to achieve the following:
+
+#### Maximize code coverage
+The configuration parameters are not hardcoded, but instead selected based on incoming data. This ensures more code paths are reached by the fuzzers.
+
+#### Maximize utilization of input data
+The plugins feed the entire input data to the module. This ensures that the plugins tolerate any kind of input (empty, huge, malformed, etc) and dont `exit()` on any input and thereby increasing the chance of identifying vulnerabilities.
+
+## Table of contents
++ [keymint_attestation_fuzzer](#KeyMintAttestation)
++ [keymint_authSet_fuzzer](#KeyMintAuthSet)
+
+# <a name="KeyMintAttestation"></a> Fuzzer for KeyMintAttestation
+KeyMintAttestation supports the following parameters:
+1. PaddingMode(parameter name: "padding")
+2. Digest(parameter name: "digest")
+3. Index(parameter name: "idx")
+4. Timestamp(parameter name: "timestamp")
+5. AuthSet(parameter name: "authSet")
+6. IssuerSubjectName(parameter name: "issuerSubjectName")
+7. AttestationChallenge(parameter name: "challenge")
+8. AttestationApplicationId(parameter name: "id")
+9. EcCurve(parameter name: "ecCurve")
+10. BlockMode(parameter name: "blockmode")
+11. minMacLength(parameter name: "minMacLength")
+12. macLength(parameter name: "macLength")
+
+| Parameter| Valid Values| Configured Value|
+|------------- |--------------| -------------------- |
+|`padding`| `PaddingMode` |Value obtained from FuzzedDataProvider|
+|`digest`| `Digest` |Value obtained from FuzzedDataProvider|
+|`idx`| `size_t` |Value obtained from FuzzedDataProvider|
+|`timestamp`| `uint64_t` |Value obtained from FuzzedDataProvider|
+|`authSet`| `uint32_t` |Value obtained from FuzzedDataProvider|
+|`issuerSubjectName`| `uint8_t` |Value obtained from FuzzedDataProvider|
+|`AttestationChallenge`| `string` |Value obtained from FuzzedDataProvider|
+|`AttestationApplicationId`| `string` |Value obtained from FuzzedDataProvider|
+|`blockmode`| `BlockMode` |Value obtained from FuzzedDataProvider|
+|`minMacLength`| `uint32_t` |Value obtained from FuzzedDataProvider|
+|`macLength`| `uint32_t` |Value obtained from FuzzedDataProvider|
+
+#### Steps to run
+1. Build the fuzzer
+```
+$ mm -j$(nproc) keymint_attestation_fuzzer
+```
+2. Run on device
+```
+$ adb sync data
+$ adb shell /data/fuzz/arm64/keymint_attestation_fuzzer/keymint_attestation_fuzzer
+```
+
+# <a name="KeyMintAuthSet"></a> Fuzzer for KeyMintAuthSet
+KeyMintAuthSet supports the following parameters:
+1. AuthorizationSet(parameter name: "authSet")
+2. AuthorizationSet(parameter name: "params")
+3. KeyParameters(parameter name: "numKeyParam")
+4. Tag(parameter name: "tag")
+
+| Parameter| Valid Values| Configured Value|
+|------------- |--------------| -------------------- |
+|`authSet`| `AuthorizationSet` |Value obtained from FuzzedDataProvider|
+|`params`| `AuthorizationSet` |Value obtained from FuzzedDataProvider|
+|`numKeyParam`| `size_t` |Value obtained from FuzzedDataProvider|
+|`tag`| `Tag` |Value obtained from FuzzedDataProvider|
+
+#### Steps to run
+1. Build the fuzzer
+```
+$ mm -j$(nproc) keymint_authSet_fuzzer
+```
+2. Run on device
+```
+$ adb sync data
+$ adb shell /data/fuzz/arm64/keymint_authSet_fuzzer/keymint_authSet_fuzzer
+```
diff --git a/security/keymint/support/fuzzer/keymint_attestation_fuzzer.cpp b/security/keymint/support/fuzzer/keymint_attestation_fuzzer.cpp
new file mode 100644
index 0000000..bd781ac
--- /dev/null
+++ b/security/keymint/support/fuzzer/keymint_attestation_fuzzer.cpp
@@ -0,0 +1,165 @@
+/*
+ * 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.
+ *
+ */
+
+#include <aidl/android/hardware/security/keymint/AttestationKey.h>
+#include <aidl/android/hardware/security/keymint/KeyCreationResult.h>
+#include <android/binder_manager.h>
+#include <keymint_common.h>
+#include <keymint_support/attestation_record.h>
+#include <keymint_support/openssl_utils.h>
+#include <utils/Log.h>
+
+namespace android::hardware::security::keymint_support::fuzzer {
+using namespace android;
+using AStatus = ::ndk::ScopedAStatus;
+std::shared_ptr<IKeyMintDevice> gKeyMint = nullptr;
+
+constexpr size_t kMaxBytes = 256;
+const std::string kServiceName = "android.hardware.security.keymint.IKeyMintDevice/default";
+
+class KeyMintAttestationFuzzer {
+ public:
+ KeyMintAttestationFuzzer(const uint8_t* data, size_t size) : mFdp(data, size){};
+ void process();
+
+ private:
+ KeyCreationResult generateKey(const AuthorizationSet& keyDesc,
+ const std::optional<AttestationKey>& attestKey,
+ vector<uint8_t>* keyBlob,
+ vector<KeyCharacteristics>* keyCharacteristics,
+ vector<Certificate>* certChain);
+ X509_Ptr parseCertificateBlob(const vector<uint8_t>& blob);
+ ASN1_OCTET_STRING* getAttestationRecord(const X509* certificate);
+ bool verifyAttestationRecord(const vector<uint8_t>& attestationCert);
+ FuzzedDataProvider mFdp;
+};
+
+KeyCreationResult KeyMintAttestationFuzzer::generateKey(
+ const AuthorizationSet& keyDesc, const std::optional<AttestationKey>& attestKey,
+ vector<uint8_t>* keyBlob, vector<KeyCharacteristics>* keyCharacteristics,
+ vector<Certificate>* certChain) {
+ KeyCreationResult creationResult;
+ AStatus result = gKeyMint->generateKey(keyDesc.vector_data(), attestKey, &creationResult);
+ if (result.isOk() && creationResult.keyBlob.size() > 0) {
+ *keyBlob = std::move(creationResult.keyBlob);
+ *keyCharacteristics = std::move(creationResult.keyCharacteristics);
+ *certChain = std::move(creationResult.certificateChain);
+ }
+ return creationResult;
+}
+
+X509_Ptr KeyMintAttestationFuzzer::parseCertificateBlob(const vector<uint8_t>& blob) {
+ const uint8_t* data = blob.data();
+ return X509_Ptr(d2i_X509(nullptr, &data, blob.size()));
+}
+
+ASN1_OCTET_STRING* KeyMintAttestationFuzzer::getAttestationRecord(const X509* certificate) {
+ ASN1_OBJECT_Ptr oid(OBJ_txt2obj(kAttestionRecordOid, 1 /* dotted string format */));
+ if (!oid.get()) {
+ return nullptr;
+ }
+
+ int32_t location = X509_get_ext_by_OBJ(certificate, oid.get(), -1 /* search from beginning */);
+ if (location == -1) {
+ return nullptr;
+ }
+
+ X509_EXTENSION* attestRecordExt = X509_get_ext(certificate, location);
+ if (!attestRecordExt) {
+ return nullptr;
+ }
+
+ ASN1_OCTET_STRING* attestRecord = X509_EXTENSION_get_data(attestRecordExt);
+ return attestRecord;
+}
+
+bool KeyMintAttestationFuzzer::verifyAttestationRecord(const vector<uint8_t>& attestationCert) {
+ X509_Ptr cert(parseCertificateBlob(attestationCert));
+ if (!cert.get()) {
+ return false;
+ }
+
+ ASN1_OCTET_STRING* attestRecord = getAttestationRecord(cert.get());
+ if (!attestRecord) {
+ return false;
+ }
+
+ AuthorizationSet attestationSwEnforced;
+ AuthorizationSet attestationHwEnforced;
+ SecurityLevel attestationSecurityLevel;
+ SecurityLevel keymintSecurityLevel;
+ vector<uint8_t> attestationChallenge;
+ vector<uint8_t> attestationUniqueId;
+ uint32_t attestationVersion;
+ uint32_t keymintVersion;
+
+ auto error = parse_attestation_record(attestRecord->data, attestRecord->length,
+ &attestationVersion, &attestationSecurityLevel,
+ &keymintVersion, &keymintSecurityLevel,
+ &attestationChallenge, &attestationSwEnforced,
+ &attestationHwEnforced, &attestationUniqueId);
+ if (error != ErrorCode::OK) {
+ return false;
+ }
+
+ VerifiedBoot verifiedBootState;
+ vector<uint8_t> verifiedBootKey;
+ vector<uint8_t> verifiedBootHash;
+ bool device_locked;
+
+ error = parse_root_of_trust(attestRecord->data, attestRecord->length, &verifiedBootKey,
+ &verifiedBootState, &device_locked, &verifiedBootHash);
+ if (error != ErrorCode::OK) {
+ return false;
+ }
+ return true;
+}
+
+void KeyMintAttestationFuzzer::process() {
+ AttestationKey attestKey;
+ vector<Certificate> attestKeyCertChain;
+ vector<KeyCharacteristics> attestKeyCharacteristics;
+ generateKey(createAuthSetForAttestKey(&mFdp), {}, &attestKey.keyBlob, &attestKeyCharacteristics,
+ &attestKeyCertChain);
+
+ vector<Certificate> attestedKeyCertChain;
+ vector<KeyCharacteristics> attestedKeyCharacteristics;
+ vector<uint8_t> attestedKeyBlob;
+ attestKey.issuerSubjectName = mFdp.ConsumeBytes<uint8_t>(kMaxBytes);
+ generateKey(createAuthorizationSet(&mFdp), attestKey, &attestedKeyBlob,
+ &attestedKeyCharacteristics, &attestedKeyCertChain);
+
+ if (attestedKeyCertChain.size() > 0) {
+ size_t leafCert = attestedKeyCertChain.size() - 1;
+ verifyAttestationRecord(attestedKeyCertChain[leafCert].encodedCertificate);
+ }
+}
+
+extern "C" int LLVMFuzzerInitialize(int /* *argc */, char /* ***argv */) {
+ ::ndk::SpAIBinder binder(AServiceManager_waitForService(kServiceName.c_str()));
+ gKeyMint = std::move(IKeyMintDevice::fromBinder(binder));
+ LOG_ALWAYS_FATAL_IF(!gKeyMint, "Failed to get IKeyMintDevice instance.");
+ return 0;
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ KeyMintAttestationFuzzer kmAttestationFuzzer(data, size);
+ kmAttestationFuzzer.process();
+ return 0;
+}
+
+} // namespace android::hardware::security::keymint_support::fuzzer
diff --git a/security/keymint/support/fuzzer/keymint_authSet_fuzzer.cpp b/security/keymint/support/fuzzer/keymint_authSet_fuzzer.cpp
new file mode 100644
index 0000000..fcc3d91
--- /dev/null
+++ b/security/keymint/support/fuzzer/keymint_authSet_fuzzer.cpp
@@ -0,0 +1,175 @@
+/*
+ * 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.
+ *
+ */
+#include <keymint_common.h>
+#include <fstream>
+
+namespace android::hardware::security::keymint_support::fuzzer {
+
+constexpr size_t kMinAction = 0;
+constexpr size_t kMaxAction = 10;
+constexpr size_t kMinKeyParameter = 1;
+constexpr size_t kMaxKeyParameter = 10;
+
+constexpr Tag kTagArray[] = {Tag::INVALID,
+ Tag::PURPOSE,
+ Tag::ALGORITHM,
+ Tag::KEY_SIZE,
+ Tag::BLOCK_MODE,
+ Tag::DIGEST,
+ Tag::PADDING,
+ Tag::CALLER_NONCE,
+ Tag::MIN_MAC_LENGTH,
+ Tag::EC_CURVE,
+ Tag::RSA_PUBLIC_EXPONENT,
+ Tag::INCLUDE_UNIQUE_ID,
+ Tag::RSA_OAEP_MGF_DIGEST,
+ Tag::BOOTLOADER_ONLY,
+ Tag::ROLLBACK_RESISTANCE,
+ Tag::HARDWARE_TYPE,
+ Tag::EARLY_BOOT_ONLY,
+ Tag::ACTIVE_DATETIME,
+ Tag::ORIGINATION_EXPIRE_DATETIME,
+ Tag::USAGE_EXPIRE_DATETIME,
+ Tag::MIN_SECONDS_BETWEEN_OPS,
+ Tag::MAX_USES_PER_BOOT,
+ Tag::USAGE_COUNT_LIMIT,
+ Tag::USER_ID,
+ Tag::USER_SECURE_ID,
+ Tag::NO_AUTH_REQUIRED,
+ Tag::USER_AUTH_TYPE,
+ Tag::AUTH_TIMEOUT,
+ Tag::ALLOW_WHILE_ON_BODY,
+ Tag::TRUSTED_USER_PRESENCE_REQUIRED,
+ Tag::TRUSTED_CONFIRMATION_REQUIRED,
+ Tag::UNLOCKED_DEVICE_REQUIRED,
+ Tag::APPLICATION_ID,
+ Tag::APPLICATION_DATA,
+ Tag::CREATION_DATETIME,
+ Tag::ORIGIN,
+ Tag::ROOT_OF_TRUST,
+ Tag::OS_VERSION,
+ Tag::OS_PATCHLEVEL,
+ Tag::UNIQUE_ID,
+ Tag::ATTESTATION_CHALLENGE,
+ Tag::ATTESTATION_APPLICATION_ID,
+ Tag::ATTESTATION_ID_BRAND,
+ Tag::ATTESTATION_ID_DEVICE,
+ Tag::ATTESTATION_ID_PRODUCT,
+ Tag::ATTESTATION_ID_SERIAL,
+ Tag::ATTESTATION_ID_IMEI,
+ Tag::ATTESTATION_ID_MEID,
+ Tag::ATTESTATION_ID_MANUFACTURER,
+ Tag::ATTESTATION_ID_MODEL,
+ Tag::VENDOR_PATCHLEVEL,
+ Tag::BOOT_PATCHLEVEL,
+ Tag::DEVICE_UNIQUE_ATTESTATION,
+ Tag::IDENTITY_CREDENTIAL_KEY,
+ Tag::STORAGE_KEY,
+ Tag::ASSOCIATED_DATA,
+ Tag::NONCE,
+ Tag::MAC_LENGTH,
+ Tag::RESET_SINCE_ID_ROTATION,
+ Tag::CONFIRMATION_TOKEN,
+ Tag::CERTIFICATE_SERIAL,
+ Tag::CERTIFICATE_SUBJECT,
+ Tag::CERTIFICATE_NOT_BEFORE,
+ Tag::CERTIFICATE_NOT_AFTER,
+ Tag::MAX_BOOT_LEVEL};
+
+class KeyMintAuthSetFuzzer {
+ public:
+ KeyMintAuthSetFuzzer(const uint8_t* data, size_t size) : mFdp(data, size){};
+ void process();
+
+ private:
+ FuzzedDataProvider mFdp;
+};
+
+void KeyMintAuthSetFuzzer::process() {
+ AuthorizationSet authSet = createAuthorizationSet(&mFdp);
+ while (mFdp.remaining_bytes()) {
+ auto invokeAuthSetAPI = mFdp.PickValueInArray<const std::function<void()>>({
+ [&]() { authSet.Sort(); },
+ [&]() { authSet.Deduplicate(); },
+ [&]() { authSet.Union(createAuthorizationSet(&mFdp)); },
+ [&]() { authSet.Subtract(createAuthorizationSet(&mFdp)); },
+ [&]() { // invoke push_back()
+ AuthorizationSetBuilder builder = AuthorizationSetBuilder();
+ for (const KeyParameter& tag : authSet) {
+ builder.push_back(tag);
+ }
+ AuthorizationSet params = createAuthorizationSet(&mFdp);
+ authSet.push_back(params);
+ },
+ [&]() { // invoke copy constructor
+ auto params = AuthorizationSetBuilder().Authorizations(authSet);
+ authSet = params;
+ },
+ [&]() { // invoke move constructor
+ auto params = AuthorizationSetBuilder().Authorizations(authSet);
+ authSet = std::move(params);
+ },
+ [&]() { // invoke Constructor from vector<KeyParameter>
+ vector<KeyParameter> keyParam;
+ size_t numKeyParam =
+ mFdp.ConsumeIntegralInRange<size_t>(kMinKeyParameter, kMaxKeyParameter);
+ keyParam.resize(numKeyParam);
+ for (size_t idx = 0; idx < numKeyParam - 1; ++idx) {
+ keyParam[idx].tag = mFdp.PickValueInArray(kTagArray);
+ }
+ if (mFdp.ConsumeBool()) {
+ AuthorizationSet auths(keyParam);
+ auths.push_back(AuthorizationSet(keyParam));
+ } else { // invoke operator=
+ AuthorizationSet auths = keyParam;
+ }
+ },
+ [&]() { // invoke 'Contains()'
+ Tag tag = Tag::INVALID;
+ if (authSet.size() > 0) {
+ tag = authSet[mFdp.ConsumeIntegralInRange<size_t>(0, authSet.size() - 1)]
+ .tag;
+ }
+ authSet.Contains(mFdp.ConsumeBool() ? tag : mFdp.PickValueInArray(kTagArray));
+ },
+ [&]() { // invoke 'GetTagCount()'
+ Tag tag = Tag::INVALID;
+ if (authSet.size() > 0) {
+ tag = authSet[mFdp.ConsumeIntegralInRange<size_t>(0, authSet.size() - 1)]
+ .tag;
+ }
+ authSet.GetTagCount(mFdp.ConsumeBool() ? tag
+ : mFdp.PickValueInArray(kTagArray));
+ },
+ [&]() { // invoke 'erase()'
+ if (authSet.size() > 0) {
+ authSet.erase(mFdp.ConsumeIntegralInRange<size_t>(0, authSet.size() - 1));
+ }
+ },
+ });
+ invokeAuthSetAPI();
+ }
+ authSet.Clear();
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ KeyMintAuthSetFuzzer kmAuthSetFuzzer(data, size);
+ kmAuthSetFuzzer.process();
+ return 0;
+}
+
+} // namespace android::hardware::security::keymint_support::fuzzer
diff --git a/security/keymint/support/fuzzer/keymint_common.h b/security/keymint/support/fuzzer/keymint_common.h
new file mode 100644
index 0000000..5c30e38
--- /dev/null
+++ b/security/keymint/support/fuzzer/keymint_common.h
@@ -0,0 +1,260 @@
+/*
+ * 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.
+ *
+ */
+#ifndef __KEYMINT_COMMON_H__
+#define __KEYMINT_COMMON_H__
+
+#include <aidl/android/hardware/security/keymint/BlockMode.h>
+#include <aidl/android/hardware/security/keymint/Digest.h>
+#include <aidl/android/hardware/security/keymint/EcCurve.h>
+#include <aidl/android/hardware/security/keymint/PaddingMode.h>
+#include <fuzzer/FuzzedDataProvider.h>
+#include <keymint_support/authorization_set.h>
+
+namespace android::hardware::security::keymint_support::fuzzer {
+
+using namespace aidl::android::hardware::security::keymint;
+
+constexpr uint32_t kStringSize = 64;
+constexpr uint32_t k3DesKeySize = 168;
+constexpr uint32_t kSymmKeySize = 256;
+constexpr uint32_t kRsaKeySize = 2048;
+constexpr uint32_t kPublicExponent = 65537;
+
+constexpr EcCurve kCurve[] = {EcCurve::P_224, EcCurve::P_256, EcCurve::P_384, EcCurve::P_521,
+ EcCurve::CURVE_25519};
+
+constexpr PaddingMode kPaddingMode[] = {
+ PaddingMode::NONE,
+ PaddingMode::RSA_OAEP,
+ PaddingMode::RSA_PSS,
+ PaddingMode::RSA_PKCS1_1_5_ENCRYPT,
+ PaddingMode::RSA_PKCS1_1_5_SIGN,
+ PaddingMode::PKCS7,
+};
+
+constexpr Digest kDigest[] = {
+ Digest::NONE, Digest::MD5, Digest::SHA1, Digest::SHA_2_224,
+ Digest::SHA_2_256, Digest::SHA_2_384, Digest::SHA_2_512,
+};
+
+constexpr BlockMode kBlockMode[] = {
+ BlockMode::ECB,
+ BlockMode::CBC,
+ BlockMode::CTR,
+ BlockMode::GCM,
+};
+
+enum AttestAuthSet : uint32_t {
+ RSA_ATTEST_KEY = 0u,
+ ECDSA_ATTEST_KEY,
+};
+
+enum AuthSet : uint32_t {
+ RSA_KEY = 0u,
+ RSA_SIGNING_KEY,
+ RSA_ENCRYPTION_KEY,
+ ECDSA_SIGNING_CURVE,
+ AES_ENCRYPTION_KEY,
+ TRIPLE_DES,
+ HMAC,
+ NO_DIGEST,
+ ECB_MODE,
+ GSM_MODE_MIN_MAC,
+ GSM_MODE_MAC,
+ BLOCK_MODE,
+};
+
+AuthorizationSet createAuthSetForAttestKey(FuzzedDataProvider* dataProvider) {
+ uint32_t attestAuthSet = dataProvider->ConsumeBool() ? AttestAuthSet::RSA_ATTEST_KEY
+ : AttestAuthSet::ECDSA_ATTEST_KEY;
+ uint64_t timestamp = dataProvider->ConsumeIntegral<uint64_t>();
+ Digest digest = dataProvider->PickValueInArray(kDigest);
+ PaddingMode padding = dataProvider->PickValueInArray(kPaddingMode);
+ std::string challenge = dataProvider->ConsumeRandomLengthString(kStringSize);
+ std::string id = dataProvider->ConsumeRandomLengthString(kStringSize);
+ switch (attestAuthSet) {
+ case RSA_ATTEST_KEY: {
+ return AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .RsaKey(kRsaKeySize, kPublicExponent)
+ .Digest(digest)
+ .Padding(padding)
+ .AttestKey()
+ .AttestationChallenge(challenge)
+ .AttestationApplicationId(id)
+ .SetDefaultValidity()
+ .Authorization(TAG_CREATION_DATETIME, timestamp)
+ .Authorization(TAG_INCLUDE_UNIQUE_ID)
+ .Authorization(TAG_PURPOSE, KeyPurpose::ATTEST_KEY);
+ } break;
+ case ECDSA_ATTEST_KEY: {
+ EcCurve ecCurve = dataProvider->PickValueInArray(kCurve);
+ return AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .EcdsaKey(ecCurve)
+ .AttestKey()
+ .Digest(digest)
+ .AttestationChallenge(challenge)
+ .AttestationApplicationId(id)
+ .SetDefaultValidity()
+ .Authorization(TAG_CREATION_DATETIME, timestamp)
+ .Authorization(TAG_INCLUDE_UNIQUE_ID)
+ .Authorization(TAG_PURPOSE, KeyPurpose::ATTEST_KEY);
+ } break;
+ default:
+ break;
+ };
+ return AuthorizationSetBuilder();
+}
+
+AuthorizationSet createAuthorizationSet(FuzzedDataProvider* dataProvider) {
+ uint32_t authSet =
+ dataProvider->ConsumeIntegralInRange<uint32_t>(AuthSet::RSA_KEY, AuthSet::BLOCK_MODE);
+ uint64_t timestamp = dataProvider->ConsumeIntegral<uint64_t>();
+ Digest digest = dataProvider->PickValueInArray(kDigest);
+ PaddingMode padding = dataProvider->PickValueInArray(kPaddingMode);
+ std::string challenge = dataProvider->ConsumeRandomLengthString(kStringSize);
+ std::string id = dataProvider->ConsumeRandomLengthString(kStringSize);
+ switch (authSet) {
+ case RSA_KEY: {
+ return AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .RsaKey(kRsaKeySize, kPublicExponent)
+ .Digest(digest)
+ .Padding(padding)
+ .AttestKey()
+ .AttestationChallenge(challenge)
+ .AttestationApplicationId(id)
+ .SetDefaultValidity()
+ .Authorization(TAG_CREATION_DATETIME, timestamp)
+ .Authorization(TAG_INCLUDE_UNIQUE_ID);
+ } break;
+ case RSA_SIGNING_KEY: {
+ return AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .RsaSigningKey(kRsaKeySize, kPublicExponent)
+ .Digest(digest)
+ .Padding(padding)
+ .AttestationChallenge(challenge)
+ .AttestationApplicationId(id)
+ .SetDefaultValidity()
+ .Authorization(TAG_CREATION_DATETIME, timestamp)
+ .Authorization(TAG_INCLUDE_UNIQUE_ID);
+ } break;
+ case RSA_ENCRYPTION_KEY: {
+ return AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .RsaEncryptionKey(kRsaKeySize, kPublicExponent)
+ .Digest(digest)
+ .Padding(padding)
+ .AttestationChallenge(challenge)
+ .AttestationApplicationId(id)
+ .SetDefaultValidity()
+ .Authorization(TAG_CREATION_DATETIME, timestamp)
+ .Authorization(TAG_INCLUDE_UNIQUE_ID);
+ } break;
+ case ECDSA_SIGNING_CURVE: {
+ EcCurve ecCurve = dataProvider->PickValueInArray(kCurve);
+ return AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .EcdsaSigningKey(ecCurve)
+ .Digest(digest)
+ .AttestationChallenge(challenge)
+ .AttestationApplicationId(id)
+ .SetDefaultValidity()
+ .Authorization(TAG_CREATION_DATETIME, timestamp)
+ .Authorization(TAG_INCLUDE_UNIQUE_ID);
+ } break;
+ case AES_ENCRYPTION_KEY: {
+ BlockMode blockmode = dataProvider->PickValueInArray(kBlockMode);
+ return AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .AesEncryptionKey(kSymmKeySize)
+ .BlockMode(blockmode)
+ .Digest(digest)
+ .Padding(padding);
+ } break;
+ case TRIPLE_DES: {
+ BlockMode blockmode = dataProvider->PickValueInArray(kBlockMode);
+ return AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .TripleDesEncryptionKey(k3DesKeySize)
+ .BlockMode(blockmode)
+ .Digest(digest)
+ .Padding(padding)
+ .EcbMode()
+ .SetDefaultValidity();
+ } break;
+ case HMAC: {
+ return AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .HmacKey(kSymmKeySize)
+ .Digest(digest)
+ .Padding(padding);
+ } break;
+ case NO_DIGEST: {
+ return AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .AesEncryptionKey(kSymmKeySize)
+ .NoDigestOrPadding()
+ .Digest(digest)
+ .Padding(padding);
+ } break;
+ case ECB_MODE: {
+ return AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .AesEncryptionKey(kSymmKeySize)
+ .EcbMode()
+ .Digest(digest)
+ .Padding(padding);
+ } break;
+ case GSM_MODE_MIN_MAC: {
+ uint32_t minMacLength = dataProvider->ConsumeIntegral<uint32_t>();
+ return AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .AesEncryptionKey(kSymmKeySize)
+ .GcmModeMinMacLen(minMacLength)
+ .Digest(digest)
+ .Padding(padding);
+ } break;
+ case GSM_MODE_MAC: {
+ uint32_t macLength = dataProvider->ConsumeIntegral<uint32_t>();
+ return AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .AesEncryptionKey(kSymmKeySize)
+ .GcmModeMacLen(macLength)
+ .Digest(digest)
+ .Padding(padding);
+ } break;
+ case BLOCK_MODE: {
+ BlockMode blockmode = dataProvider->PickValueInArray(kBlockMode);
+ return AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .AesEncryptionKey(kSymmKeySize)
+ .BlockMode(blockmode)
+ .Digest(digest)
+ .Padding(padding);
+ } break;
+ default:
+ break;
+ };
+ return AuthorizationSetBuilder();
+}
+
+} // namespace android::hardware::security::keymint_support::fuzzer
+
+#endif // __KEYMINT_COMMON_H__