Extend onDump to support debug options.
Extend onDump to support debugging. This CL only adds
genFakeData option.
Test: atest android.hardware.automotive.vehicle@2.0-default-impl-unit-tests
Bug: 193565753
Change-Id: I11d5d0f12c0ef050544c798bff2b4b27962bd3df
diff --git a/automotive/vehicle/2.0/default/Android.bp b/automotive/vehicle/2.0/default/Android.bp
index aabc60c..2e8ca66 100644
--- a/automotive/vehicle/2.0/default/Android.bp
+++ b/automotive/vehicle/2.0/default/Android.bp
@@ -197,6 +197,7 @@
static_libs: [
"libbase",
"libcutils",
+ "libgmock",
"libjsoncpp",
"libprotobuf-cpp-lite",
],
@@ -212,6 +213,7 @@
"android.hardware.automotive.vehicle@2.0-default-impl-lib",
"android.hardware.automotive.vehicle@2.0-libproto-native",
],
+ data: [":vhal_test_json"],
test_suites: ["general-tests"],
}
@@ -233,7 +235,7 @@
static_libs: [
"android.hardware.automotive.vehicle@2.0-manager-lib",
"android.hardware.automotive.vehicle@2.0-libproto-native",
- "//device/generic/car/emulator/vhal_v2_0:android.hardware.automotive.vehicle@2.0-emulator-impl-lib",
+ "android.hardware.automotive.vehicle@2.0-emulator-impl-lib",
],
}
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultVehicleHalServer.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultVehicleHalServer.cpp
index 66849bc..f61a93b 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultVehicleHalServer.cpp
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultVehicleHalServer.cpp
@@ -20,6 +20,8 @@
#include <android-base/format.h>
#include <android-base/logging.h>
+#include <android-base/parsedouble.h>
+#include <android-base/parseint.h>
#include <utils/SystemClock.h>
#include "DefaultConfig.h"
@@ -82,7 +84,7 @@
}
}
-GeneratorHub* DefaultVehicleHalServer::getGenerator() {
+GeneratorHub* DefaultVehicleHalServer::getGeneratorHub() {
return &mGeneratorHub;
}
@@ -145,8 +147,8 @@
return StatusCode::INVALID_ARG;
}
int32_t cookie = v.int32Values[1];
- getGenerator()->registerGenerator(cookie,
- std::make_unique<LinearFakeValueGenerator>(request));
+ getGeneratorHub()->registerGenerator(
+ cookie, std::make_unique<LinearFakeValueGenerator>(request));
break;
}
case FakeDataCommand::StartJson: {
@@ -156,8 +158,12 @@
return StatusCode::INVALID_ARG;
}
int32_t cookie = std::hash<std::string>()(v.stringValue);
- getGenerator()->registerGenerator(cookie,
- std::make_unique<JsonFakeValueGenerator>(request));
+ auto generator = std::make_unique<JsonFakeValueGenerator>(request);
+ if (!generator->hasNext()) {
+ LOG(ERROR) << __func__ << ": invalid JSON file, no events";
+ return StatusCode::INVALID_ARG;
+ }
+ getGeneratorHub()->registerGenerator(cookie, std::move(generator));
break;
}
case FakeDataCommand::StopLinear: {
@@ -167,7 +173,7 @@
return StatusCode::INVALID_ARG;
}
int32_t cookie = v.int32Values[1];
- getGenerator()->unregisterGenerator(cookie);
+ getGeneratorHub()->unregisterGenerator(cookie);
break;
}
case FakeDataCommand::StopJson: {
@@ -177,7 +183,7 @@
return StatusCode::INVALID_ARG;
}
int32_t cookie = std::hash<std::string>()(v.stringValue);
- getGenerator()->unregisterGenerator(cookie);
+ getGeneratorHub()->unregisterGenerator(cookie);
break;
}
case FakeDataCommand::KeyPress: {
@@ -331,17 +337,225 @@
}
IVehicleServer::DumpResult DefaultVehicleHalServer::onDump(
- const std::vector<std::string>& /* options */) {
+ const std::vector<std::string>& options) {
DumpResult result;
- result.callerShouldDumpState = true;
-
- result.buffer += "Server side properties: \n";
- auto values = mServerSidePropStore.readAllValues();
- size_t i = 0;
- for (const auto& value : values) {
- result.buffer += fmt::format("[{}]: {}\n", i, toString(value));
- i++;
+ if (options.size() == 0) {
+ // No options, dump all stored properties.
+ result.callerShouldDumpState = true;
+ result.buffer += "Server side properties: \n";
+ auto values = mServerSidePropStore.readAllValues();
+ size_t i = 0;
+ for (const auto& value : values) {
+ result.buffer += fmt::format("[{}]: {}\n", i, toString(value));
+ i++;
+ }
+ return result;
}
+ if (options[0] != "--debughal") {
+ // We only expect "debughal" command. This might be some commands that the caller knows
+ // about, so let caller handle it.
+ result.callerShouldDumpState = true;
+ return result;
+ }
+
+ return debug(options);
+}
+
+IVehicleServer::DumpResult DefaultVehicleHalServer::debug(const std::vector<std::string>& options) {
+ DumpResult result;
+ // This is a debug command for the HAL, caller should not continue to dump state.
+ result.callerShouldDumpState = false;
+
+ if (options.size() < 2) {
+ result.buffer += "No command specified\n";
+ result.buffer += getHelpInfo();
+ return result;
+ }
+
+ std::string command = options[1];
+ if (command == "--help") {
+ result.buffer += getHelpInfo();
+ return result;
+ } else if (command == "--genfakedata") {
+ return genFakeData(options);
+ }
+
+ result.buffer += "Unknown command: \"" + command + "\"\n";
+ result.buffer += getHelpInfo();
+ return result;
+}
+
+std::string DefaultVehicleHalServer::getHelpInfo() {
+ return "Help: \n"
+ "Generate Fake Data: \n"
+ "\tStart a linear generator: \n"
+ "\t--debughal --genfakedata --startlinear [propID(int32)] [middleValue(float)] "
+ "[currentValue(float)] [dispersion(float)] [increment(float)] [interval(int64)]\n"
+ "\tStop a linear generator: \n"
+ "\t--debughal --genfakedata --stoplinear [propID(int32)]\n"
+ "\tStart a json generator: \n"
+ "\t--debughal --genfakedata --startjson [jsonFilePath(string)] "
+ "[repetition(int32)(optional)]\n"
+ "\tStop a json generator: \n"
+ "\t--debughal --genfakedata --stopjson [jsonFilePath(string)]\n"
+ "\tGenerate key press: \n"
+ "\t--debughal --genfakedata --keypress [keyCode(int32)] [display[int32]]\n";
+}
+
+IVehicleServer::DumpResult DefaultVehicleHalServer::genFakeData(
+ const std::vector<std::string>& options) {
+ DumpResult result;
+ // This is a debug command for the HAL, caller should not continue to dump state.
+ result.callerShouldDumpState = false;
+
+ if (options.size() < 3) {
+ result.buffer += "No subcommand specified for genfakedata\n";
+ result.buffer += getHelpInfo();
+ return result;
+ }
+
+ std::string command = options[2];
+ if (command == "--startlinear") {
+ LOG(INFO) << __func__ << "FakeDataCommand::StartLinear";
+ // --debughal --genfakedata --startlinear [propID(int32)] [middleValue(float)]
+ // [currentValue(float)] [dispersion(float)] [increment(float)] [interval(int64)]
+ if (options.size() != 9) {
+ result.buffer +=
+ "incorrect argument count, need 9 arguments for --genfakedata --startlinear\n";
+ result.buffer += getHelpInfo();
+ return result;
+ }
+ int32_t propId;
+ float middleValue;
+ float currentValue;
+ float dispersion;
+ float increment;
+ int64_t interval;
+ if (!android::base::ParseInt(options[3], &propId)) {
+ result.buffer += "failed to parse propdID as int: \"" + options[3] + "\"\n";
+ result.buffer += getHelpInfo();
+ return result;
+ }
+ if (!android::base::ParseFloat(options[4], &middleValue)) {
+ result.buffer += "failed to parse middleValue as float: \"" + options[4] + "\"\n";
+ result.buffer += getHelpInfo();
+ return result;
+ }
+ if (!android::base::ParseFloat(options[5], ¤tValue)) {
+ result.buffer += "failed to parse currentValue as float: \"" + options[5] + "\"\n";
+ result.buffer += getHelpInfo();
+ return result;
+ }
+ if (!android::base::ParseFloat(options[6], &dispersion)) {
+ result.buffer += "failed to parse dispersion as float: \"" + options[6] + "\"\n";
+ result.buffer += getHelpInfo();
+ return result;
+ }
+ if (!android::base::ParseFloat(options[7], &increment)) {
+ result.buffer += "failed to parse increment as float: \"" + options[7] + "\"\n";
+ result.buffer += getHelpInfo();
+ return result;
+ }
+ if (!android::base::ParseInt(options[8], &interval)) {
+ result.buffer += "failed to parse interval as int: \"" + options[8] + "\"\n";
+ result.buffer += getHelpInfo();
+ return result;
+ }
+ auto generator = std::make_unique<LinearFakeValueGenerator>(
+ propId, middleValue, currentValue, dispersion, increment, interval);
+ getGeneratorHub()->registerGenerator(propId, std::move(generator));
+ return result;
+ } else if (command == "--stoplinear") {
+ LOG(INFO) << __func__ << "FakeDataCommand::StopLinear";
+ // --debughal --genfakedata --stoplinear [propID(int32)]
+ if (options.size() != 4) {
+ result.buffer +=
+ "incorrect argument count, need 4 arguments for --genfakedata --stoplinear\n";
+ result.buffer += getHelpInfo();
+ return result;
+ }
+ int32_t propId;
+ if (!android::base::ParseInt(options[3], &propId)) {
+ result.buffer += "failed to parse propdID as int: \"" + options[3] + "\"\n";
+ result.buffer += getHelpInfo();
+ return result;
+ }
+ getGeneratorHub()->unregisterGenerator(propId);
+ return result;
+ } else if (command == "--startjson") {
+ LOG(INFO) << __func__ << "FakeDataCommand::StartJson";
+ // --debughal --genfakedata --startjson [jsonFilePath(string)] [repetition(int32)(optional)]
+ if (options.size() != 4 && options.size() != 5) {
+ result.buffer +=
+ "incorrect argument count, need 4 or 5 arguments for --genfakedata "
+ "--startjson\n";
+ result.buffer += getHelpInfo();
+ return result;
+ }
+ std::string fileName = options[3];
+ int32_t cookie = std::hash<std::string>()(fileName);
+ // Iterate infinitely if repetition number is not provided
+ int32_t repetition = -1;
+ if (options.size() == 5) {
+ if (!android::base::ParseInt(options[4], &repetition)) {
+ result.buffer += "failed to parse repetition as int: \"" + options[4] + "\"\n";
+ result.buffer += getHelpInfo();
+ return result;
+ }
+ }
+ auto generator = std::make_unique<JsonFakeValueGenerator>(fileName, repetition);
+ if (!generator->hasNext()) {
+ result.buffer += "invalid JSON file, no events";
+ return result;
+ }
+ getGeneratorHub()->registerGenerator(cookie, std::move(generator));
+ return result;
+ } else if (command == "--stopjson") {
+ LOG(INFO) << __func__ << "FakeDataCommand::StopJson";
+ // --debughal --genfakedata --stopjson [jsonFilePath(string)]
+ if (options.size() != 4) {
+ result.buffer +=
+ "incorrect argument count, need 4 arguments for --genfakedata --stopjson\n";
+ result.buffer += getHelpInfo();
+ return result;
+ }
+ std::string fileName = options[3];
+ int32_t cookie = std::hash<std::string>()(fileName);
+ getGeneratorHub()->unregisterGenerator(cookie);
+ return result;
+ } else if (command == "--keypress") {
+ LOG(INFO) << __func__ << "FakeDataCommand::KeyPress";
+ int32_t keyCode;
+ int32_t display;
+ // --debughal --genfakedata --keypress [keyCode(int32)] [display[int32]]
+ if (options.size() != 5) {
+ result.buffer +=
+ "incorrect argument count, need 5 arguments for --genfakedata --keypress\n";
+ result.buffer += getHelpInfo();
+ return result;
+ }
+ if (!android::base::ParseInt(options[3], &keyCode)) {
+ result.buffer += "failed to parse keyCode as int: \"" + options[3] + "\"\n";
+ result.buffer += getHelpInfo();
+ return result;
+ }
+ if (!android::base::ParseInt(options[4], &display)) {
+ result.buffer += "failed to parse display as int: \"" + options[4] + "\"\n";
+ result.buffer += getHelpInfo();
+ return result;
+ }
+ // Send back to HAL
+ onPropertyValueFromCar(
+ *createHwInputKeyProp(VehicleHwKeyInputAction::ACTION_DOWN, keyCode, display),
+ /*updateStatus=*/true);
+ onPropertyValueFromCar(
+ *createHwInputKeyProp(VehicleHwKeyInputAction::ACTION_UP, keyCode, display),
+ /*updateStatus=*/true);
+ return result;
+ }
+
+ result.buffer += "Unknown command: \"" + command + "\"\n";
+ result.buffer += getHelpInfo();
return result;
}
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultVehicleHalServer.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultVehicleHalServer.h
index 1a42cb8..aa6cf0b 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultVehicleHalServer.h
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultVehicleHalServer.h
@@ -52,7 +52,7 @@
protected:
using VehiclePropValuePtr = recyclable_ptr<VehiclePropValue>;
- GeneratorHub* getGenerator();
+ GeneratorHub* getGeneratorHub();
VehiclePropValuePool* getValuePool() const;
@@ -67,6 +67,12 @@
void storePropInitialValue(const ConfigDeclaration& config);
+ DumpResult debug(const std::vector<std::string>& options);
+
+ std::string getHelpInfo();
+
+ DumpResult genFakeData(const std::vector<std::string>& options);
+
protected:
GeneratorHub mGeneratorHub{
[this](const VehiclePropValue& value) { return onFakeValueGenerated(value); }};
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/JsonFakeValueGenerator.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/JsonFakeValueGenerator.cpp
index b62918f..b728d62 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/JsonFakeValueGenerator.cpp
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/JsonFakeValueGenerator.cpp
@@ -33,12 +33,37 @@
namespace impl {
+JsonFakeValueGenerator::JsonFakeValueGenerator(const std::string& path, int32_t repetition) {
+ const char* file = path.c_str();
+ std::ifstream ifs(file);
+ if (!ifs) {
+ ALOGE("%s: couldn't open %s for parsing.", __func__, file);
+ mGenCfg = {
+ .index = 0,
+ .events = {},
+ };
+ mNumOfIterations = 0;
+ return;
+ }
+ mGenCfg = {
+ .index = 0,
+ .events = parseFakeValueJson(ifs),
+ };
+ mNumOfIterations = repetition;
+}
+
JsonFakeValueGenerator::JsonFakeValueGenerator(const VehiclePropValue& request) {
const auto& v = request.value;
const char* file = v.stringValue.c_str();
std::ifstream ifs(file);
if (!ifs) {
ALOGE("%s: couldn't open %s for parsing.", __func__, file);
+ mGenCfg = {
+ .index = 0,
+ .events = {},
+ };
+ mNumOfIterations = 0;
+ return;
}
mGenCfg = {
.index = 0,
@@ -48,10 +73,16 @@
mNumOfIterations = v.int32Values.size() < 2 ? -1 : v.int32Values[1];
}
-JsonFakeValueGenerator::JsonFakeValueGenerator(std::string path) {
+JsonFakeValueGenerator::JsonFakeValueGenerator(const std::string& path) {
std::ifstream ifs(path);
if (!ifs) {
ALOGE("%s: couldn't open %s for parsing.", __func__, path.c_str());
+ mGenCfg = {
+ .index = 0,
+ .events = {},
+ };
+ mNumOfIterations = 0;
+ return;
}
mGenCfg = {
.index = 0,
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/JsonFakeValueGenerator.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/JsonFakeValueGenerator.h
index dc8ff66..caa3417 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/JsonFakeValueGenerator.h
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/JsonFakeValueGenerator.h
@@ -41,7 +41,8 @@
public:
JsonFakeValueGenerator(const VehiclePropValue& request);
- JsonFakeValueGenerator(std::string path);
+ JsonFakeValueGenerator(const std::string& path, int32_t repetition);
+ JsonFakeValueGenerator(const std::string& path);
~JsonFakeValueGenerator() = default;
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/LinearFakeValueGenerator.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/LinearFakeValueGenerator.cpp
index 96aaafe..a2278bd 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/LinearFakeValueGenerator.cpp
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/LinearFakeValueGenerator.cpp
@@ -29,23 +29,36 @@
namespace impl {
+LinearFakeValueGenerator::LinearFakeValueGenerator(int32_t propId, float middleValue,
+ float currentValue, float dispersion,
+ float increment, int64_t interval) {
+ initGenCfg(propId, middleValue, currentValue, dispersion, increment, interval);
+}
+
LinearFakeValueGenerator::LinearFakeValueGenerator(const VehiclePropValue& request) {
const auto& v = request.value;
+ initGenCfg(v.int32Values[1], v.floatValues[0], v.floatValues[0], v.floatValues[1],
+ v.floatValues[2], v.int64Values[0]);
+}
+
+void LinearFakeValueGenerator::initGenCfg(int32_t propId, float middleValue, float currentValue,
+ float dispersion, float increment, int64_t interval) {
+ if (currentValue < middleValue - dispersion || currentValue >= middleValue + dispersion) {
+ ALOGW("%s: invalid initValue: %f, out of range, default to %f", __func__, currentValue,
+ middleValue);
+ currentValue = middleValue;
+ }
mGenCfg = GeneratorCfg{
- .propId = v.int32Values[1],
- .initialValue = v.floatValues[0],
- .currentValue = v.floatValues[0],
- .dispersion = v.floatValues[1],
- .increment = v.floatValues[2],
- .interval = Nanos(v.int64Values[0]),
+ .propId = propId,
+ .middleValue = middleValue,
+ .currentValue = currentValue,
+ .dispersion = dispersion,
+ .increment = increment,
+ .interval = Nanos(interval),
};
}
VehiclePropValue LinearFakeValueGenerator::nextEvent() {
- mGenCfg.currentValue += mGenCfg.increment;
- if (mGenCfg.currentValue > mGenCfg.initialValue + mGenCfg.dispersion) {
- mGenCfg.currentValue = mGenCfg.initialValue - mGenCfg.dispersion;
- }
// TODO: (chenhaosjtuacm) remove "{}" if AGL compiler updated
VehiclePropValue event = {.timestamp = {}, .areaId = {}, .prop = mGenCfg.propId};
auto& value = event.value;
@@ -67,6 +80,12 @@
}
TimePoint eventTime = Clock::now() + mGenCfg.interval;
event.timestamp = eventTime.time_since_epoch().count();
+
+ mGenCfg.currentValue += mGenCfg.increment;
+ if (mGenCfg.currentValue >= mGenCfg.middleValue + mGenCfg.dispersion) {
+ // Wrap around, (i - d) + c - (i + d) = c - 2 * d
+ mGenCfg.currentValue = mGenCfg.currentValue - 2 * mGenCfg.dispersion;
+ }
return event;
}
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/LinearFakeValueGenerator.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/LinearFakeValueGenerator.h
index d3b666d..d870209 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/LinearFakeValueGenerator.h
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/LinearFakeValueGenerator.h
@@ -35,8 +35,8 @@
struct GeneratorCfg {
int32_t propId;
- float initialValue;
- float currentValue; // Should be in range (initialValue +/- dispersion).
+ float middleValue;
+ float currentValue; // Should be in range (middleValue +/- dispersion).
float dispersion; // Defines minimum and maximum value based on initial value.
float increment; // Value that we will be added to currentValue with each timer tick.
Nanos interval;
@@ -44,6 +44,11 @@
public:
LinearFakeValueGenerator(const VehiclePropValue& request);
+ // A linear value generator in range [middleValue - dispersion, middleValue + dispersion),
+ // starts at 'currentValue' and at each 'interval', increase by 'increment' and loop back if
+ // exceeds middleValue + dispersion.
+ LinearFakeValueGenerator(int32_t propId, float middleValue, float currentValue,
+ float dispersion, float increment, int64_t interval);
~LinearFakeValueGenerator() = default;
VehiclePropValue nextEvent();
@@ -52,6 +57,9 @@
private:
GeneratorCfg mGenCfg;
+
+ void initGenCfg(int32_t propId, float middleValue, float currentValue, float dispersion,
+ float increment, int64_t interval);
};
} // namespace impl
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/tests/Android.bp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/tests/Android.bp
new file mode 100644
index 0000000..5762223
--- /dev/null
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/tests/Android.bp
@@ -0,0 +1,18 @@
+// Copyright (C) 2021 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.
+
+filegroup {
+ name: "vhal_test_json",
+ srcs: ["prop.json"],
+}
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/tests/DefaultVhalImpl_test.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/tests/DefaultVhalImpl_test.cpp
index a2ec0dd..3b0d5fb 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/tests/DefaultVhalImpl_test.cpp
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/tests/DefaultVhalImpl_test.cpp
@@ -14,7 +14,9 @@
* limitations under the License.
*/
+#include <android-base/file.h>
#include <android/hardware/automotive/vehicle/2.0/types.h>
+#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <sys/mman.h>
#include <vhal_v2_0/ConcurrentQueue.h>
@@ -33,6 +35,7 @@
using ::android::hardware::automotive::vehicle::V2_0::FuelType;
using ::android::hardware::automotive::vehicle::V2_0::recyclable_ptr;
using ::android::hardware::automotive::vehicle::V2_0::StatusCode;
+using ::android::hardware::automotive::vehicle::V2_0::VehicleHwKeyInputAction;
using ::android::hardware::automotive::vehicle::V2_0::VehiclePropConfig;
using ::android::hardware::automotive::vehicle::V2_0::VehicleProperty;
using ::android::hardware::automotive::vehicle::V2_0::VehiclePropertyStatus;
@@ -44,8 +47,13 @@
using ::android::hardware::automotive::vehicle::V2_0::impl::HVAC_LEFT;
using ::android::hardware::automotive::vehicle::V2_0::impl::kMixedTypePropertyForTest;
+using ::testing::HasSubstr;
+
using VehiclePropValuePtr = recyclable_ptr<VehiclePropValue>;
+// The maximum length of property ID in string.
+const size_t MAX_PROP_ID_LENGTH = 100;
+
class DefaultVhalImplTest : public ::testing::Test {
public:
~DefaultVhalImplTest() { mEventQueue.deactivate(); }
@@ -90,7 +98,7 @@
auto gotValue = mHal->get(value, &status);
EXPECT_EQ(StatusCode::OK, status);
- EXPECT_EQ((unsigned int)1, gotValue->value.floatValues.size());
+ ASSERT_EQ((unsigned int)1, gotValue->value.floatValues.size());
EXPECT_EQ(15000.0f, gotValue->value.floatValues[0]);
}
@@ -102,7 +110,7 @@
auto gotValue = mHal->get(value, &status);
EXPECT_EQ(StatusCode::OK, status);
- EXPECT_EQ((unsigned int)1, gotValue->value.int32Values.size());
+ ASSERT_EQ((unsigned int)1, gotValue->value.int32Values.size());
EXPECT_EQ((int)FuelType::FUEL_TYPE_UNLEADED, gotValue->value.int32Values[0]);
}
@@ -114,7 +122,7 @@
auto gotValue = mHal->get(value, &status);
EXPECT_EQ(StatusCode::OK, status);
- EXPECT_EQ((unsigned int)1, gotValue->value.int32Values.size());
+ ASSERT_EQ((unsigned int)1, gotValue->value.int32Values.size());
EXPECT_EQ(2020, gotValue->value.int32Values[0]);
}
@@ -146,11 +154,11 @@
value.value.floatValues[0] = 1.0f;
StatusCode status = mHal->set(value);
- EXPECT_EQ(StatusCode::OK, status);
+ ASSERT_EQ(StatusCode::OK, status);
auto gotValue = mHal->get(value, &status);
EXPECT_EQ(StatusCode::OK, status);
- EXPECT_EQ((unsigned int)1, gotValue->value.floatValues.size());
+ ASSERT_EQ((unsigned int)1, gotValue->value.floatValues.size());
EXPECT_EQ(1.0f, gotValue->value.floatValues[0]);
}
@@ -161,11 +169,11 @@
value.value.int32Values[0] = (int)FuelType::FUEL_TYPE_LEADED;
StatusCode status = mHal->set(value);
- EXPECT_EQ(StatusCode::OK, status);
+ ASSERT_EQ(StatusCode::OK, status);
auto gotValue = mHal->get(value, &status);
EXPECT_EQ(StatusCode::OK, status);
- EXPECT_EQ((unsigned int)1, gotValue->value.int32Values.size());
+ ASSERT_EQ((unsigned int)1, gotValue->value.int32Values.size());
EXPECT_EQ((int)FuelType::FUEL_TYPE_LEADED, gotValue->value.int32Values[0]);
}
@@ -190,7 +198,7 @@
value.value.stringValue = "My Vehicle";
StatusCode status = mHal->set(value);
- EXPECT_EQ(StatusCode::OK, status);
+ ASSERT_EQ(StatusCode::OK, status);
auto gotValue = mHal->get(value, &status);
EXPECT_EQ(StatusCode::OK, status);
@@ -212,14 +220,16 @@
value.value.floatValues[0] = 1.0f;
StatusCode status = mHal->set(value);
- EXPECT_EQ(StatusCode::OK, status);
+ ASSERT_EQ(StatusCode::OK, status);
auto gotValue = mHal->get(value, &status);
EXPECT_EQ(StatusCode::OK, status);
EXPECT_EQ("test", gotValue->value.stringValue);
+ ASSERT_EQ((size_t)3, gotValue->value.int32Values.size());
EXPECT_EQ(1, gotValue->value.int32Values[0]);
EXPECT_EQ(2, gotValue->value.int32Values[1]);
EXPECT_EQ(3, gotValue->value.int32Values[2]);
+ ASSERT_EQ((size_t)1, gotValue->value.floatValues.size());
EXPECT_EQ(1.0f, gotValue->value.floatValues[0]);
}
@@ -248,7 +258,7 @@
auto status = mHal->subscribe(toInt(VehicleProperty::PERF_VEHICLE_SPEED), 10);
- EXPECT_EQ(StatusCode::OK, status);
+ ASSERT_EQ(StatusCode::OK, status);
std::this_thread::sleep_for(std::chrono::milliseconds(500));
@@ -257,18 +267,18 @@
value.prop = toInt(VehicleProperty::PERF_VEHICLE_SPEED);
value.value.floatValues.resize(1);
value.value.floatValues[0] = 1.0f;
- EXPECT_EQ(StatusCode::OK, mHal->set(value));
+ ASSERT_EQ(StatusCode::OK, mHal->set(value));
std::this_thread::sleep_for(std::chrono::milliseconds(500));
auto events = mEventQueue.flush();
- EXPECT_LE((size_t)10, events.size());
+ ASSERT_LE((size_t)10, events.size());
// The first event should be the default value.
- EXPECT_EQ((size_t)1, events[0]->value.floatValues.size());
+ ASSERT_EQ((size_t)1, events[0]->value.floatValues.size());
EXPECT_EQ(0.0f, events[0]->value.floatValues[0]);
// The last event should be the value after update.
- EXPECT_EQ((size_t)1, events[events.size() - 1]->value.floatValues.size());
+ ASSERT_EQ((size_t)1, events[events.size() - 1]->value.floatValues.size());
EXPECT_EQ(1.0f, events[events.size() - 1]->value.floatValues[0]);
}
@@ -285,13 +295,13 @@
TEST_F(DefaultVhalImplTest, testUnsubscribe) {
auto status = mHal->subscribe(toInt(VehicleProperty::PERF_VEHICLE_SPEED), 10);
- EXPECT_EQ(StatusCode::OK, status);
+ ASSERT_EQ(StatusCode::OK, status);
// Wait for 0.5 seconds to generate some events.
std::this_thread::sleep_for(std::chrono::milliseconds(500));
status = mHal->unsubscribe(toInt(VehicleProperty::PERF_VEHICLE_SPEED));
- EXPECT_EQ(StatusCode::OK, status);
+ ASSERT_EQ(StatusCode::OK, status);
// Clear all the events.
mEventQueue.flush();
@@ -308,15 +318,20 @@
EXPECT_EQ(StatusCode::INVALID_ARG, mHal->unsubscribe(toInt(VehicleProperty::INFO_MAKE)));
}
-TEST_F(DefaultVhalImplTest, testDump) {
- hidl_vec<hidl_string> options;
- hidl_handle fd = {};
+int createMemfd(hidl_handle* fd) {
native_handle_t* handle = native_handle_create(/*numFds=*/1, /*numInts=*/0);
int memfd = memfd_create("memfile", 0);
handle->data[0] = dup(memfd);
- fd.setTo(handle, /*shouldOwn=*/true);
+ fd->setTo(handle, /*shouldOwn=*/true);
+ return memfd;
+}
- EXPECT_TRUE(mHal->dump(fd, options));
+TEST_F(DefaultVhalImplTest, testDump) {
+ hidl_vec<hidl_string> options;
+ hidl_handle fd = {};
+ int memfd = createMemfd(&fd);
+
+ ASSERT_TRUE(mHal->dump(fd, options));
lseek(memfd, 0, SEEK_SET);
char buf[10240] = {};
@@ -328,12 +343,12 @@
StatusCode status;
value.prop = toInt(VehicleProperty::INFO_MAKE);
auto gotValue = mHal->get(value, &status);
- EXPECT_EQ(StatusCode::OK, status);
+ ASSERT_EQ(StatusCode::OK, status);
// Server side prop store does not have timestamp.
gotValue->timestamp = 0;
std::string infoMake = toString(*gotValue);
- EXPECT_NE(std::string::npos, std::string(buf).find(infoMake));
+ EXPECT_THAT(std::string(buf), HasSubstr(infoMake));
}
class DefaultVhalImplSetInvalidPropTest : public DefaultVhalImplTest,
@@ -484,4 +499,229 @@
return info.param.name;
});
+std::string getPropIdString(VehicleProperty prop) {
+ char s[MAX_PROP_ID_LENGTH] = {};
+ snprintf(s, sizeof(s), "%d", toInt(prop));
+ return std::string(s);
+}
+
+struct OptionsTestCase {
+ std::string name;
+ hidl_vec<hidl_string> options;
+ std::string expectMsg;
+};
+
+class DefaultVhalImplOptionsTest : public DefaultVhalImplTest,
+ public testing::WithParamInterface<OptionsTestCase> {};
+
+TEST_P(DefaultVhalImplOptionsTest, testInvalidOptions) {
+ auto tc = GetParam();
+ hidl_handle fd = {};
+ int memfd = createMemfd(&fd);
+
+ bool shouldDump = mHal->dump(fd, tc.options);
+
+ EXPECT_FALSE(shouldDump);
+ char buf[10240] = {};
+ lseek(memfd, 0, SEEK_SET);
+ read(memfd, buf, sizeof(buf));
+ EXPECT_THAT(std::string(buf), HasSubstr(tc.expectMsg));
+}
+
+std::vector<OptionsTestCase> GenInvalidOptions() {
+ return {{"no_command", {"--debughal"}, "No command specified"},
+ {"unknown_command", {"--debughal", "--unknown"}, "Unknown command: \"--unknown\""},
+ {"help", {"--debughal", "--help"}, "Help:"},
+ {"genfakedata_no_subcommand",
+ {"--debughal", "--genfakedata"},
+ "No subcommand specified for genfakedata"},
+ {"genfakedata_unknown_subcommand",
+ {"--debughal", "--genfakedata", "--unknown"},
+ "Unknown command: \"--unknown\""},
+ {"genfakedata_start_linear_no_args",
+ {"--debughal", "--genfakedata", "--startlinear"},
+ "incorrect argument count"},
+ {"genfakedata_start_linear_invalid_propId",
+ {"--debughal", "--genfakedata", "--startlinear", "abcd", "0.1", "0.1", "0.1", "0.1",
+ "100000000"},
+ "failed to parse propdID as int: \"abcd\""},
+ {"genfakedata_start_linear_invalid_middleValue",
+ {"--debughal", "--genfakedata", "--startlinear", "1", "abcd", "0.1", "0.1", "0.1",
+ "100000000"},
+ "failed to parse middleValue as float: \"abcd\""},
+ {"genfakedata_start_linear_invalid_currentValue",
+ {"--debughal", "--genfakedata", "--startlinear", "1", "0.1", "abcd", "0.1", "0.1",
+ "100000000"},
+ "failed to parse currentValue as float: \"abcd\""},
+ {"genfakedata_start_linear_invalid_dispersion",
+ {"--debughal", "--genfakedata", "--startlinear", "1", "0.1", "0.1", "abcd", "0.1",
+ "100000000"},
+ "failed to parse dispersion as float: \"abcd\""},
+ {"genfakedata_start_linear_invalid_increment",
+ {"--debughal", "--genfakedata", "--startlinear", "1", "0.1", "0.1", "0.1", "abcd",
+ "100000000"},
+ "failed to parse increment as float: \"abcd\""},
+ {"genfakedata_start_linear_invalid_interval",
+ {"--debughal", "--genfakedata", "--startlinear", "1", "0.1", "0.1", "0.1", "0.1",
+ "0.1"},
+ "failed to parse interval as int: \"0.1\""},
+ {"genfakedata_stop_linear_no_args",
+ {"--debughal", "--genfakedata", "--stoplinear"},
+ "incorrect argument count"},
+ {"genfakedata_stop_linear_invalid_propId",
+ {"--debughal", "--genfakedata", "--stoplinear", "abcd"},
+ "failed to parse propdID as int: \"abcd\""},
+ {"genfakedata_startjson_no_args",
+ {"--debughal", "--genfakedata", "--startjson"},
+ "incorrect argument count"},
+ {"genfakedata_startjson_invalid_repetition",
+ {"--debughal", "--genfakedata", "--startjson", "file", "0.1"},
+ "failed to parse repetition as int: \"0.1\""},
+ {"genfakedata_startjson_invalid_json_file",
+ {"--debughal", "--genfakedata", "--startjson", "file", "1"},
+ "invalid JSON file"},
+ {"genfakedata_stopjson_no_args",
+ {"--debughal", "--genfakedata", "--stopjson"},
+ "incorrect argument count"},
+ {"genfakedata_keypress_no_args",
+ {"--debughal", "--genfakedata", "--keypress"},
+ "incorrect argument count"},
+ {"genfakedata_keypress_invalid_keyCode",
+ {"--debughal", "--genfakedata", "--keypress", "0.1", "1"},
+ "failed to parse keyCode as int: \"0.1\""},
+ {"genfakedata_keypress_invalid_display",
+ {"--debughal", "--genfakedata", "--keypress", "1", "0.1"},
+ "failed to parse display as int: \"0.1\""}};
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ DefaultVhalImplOptionsTests, DefaultVhalImplOptionsTest,
+ testing::ValuesIn(GenInvalidOptions()),
+ [](const testing::TestParamInfo<DefaultVhalImplOptionsTest::ParamType>& info) {
+ return info.param.name;
+ });
+
+TEST_F(DefaultVhalImplTest, testDebugGenFakeDataLinear) {
+ // Start a fake linear data generator for vehicle speed at 0.1s interval.
+ // range: 0 - 100, current value: 30, step: 20.
+ hidl_vec<hidl_string> options = {"--debughal",
+ "--genfakedata",
+ "--startlinear",
+ getPropIdString(VehicleProperty::PERF_VEHICLE_SPEED),
+ /*middleValue=*/"50",
+ /*currentValue=*/"30",
+ /*dispersion=*/"50",
+ /*increment=*/"20",
+ /*interval=*/"100000000"};
+ hidl_handle fd = {};
+ int memfd = createMemfd(&fd);
+ // Clear existing events.
+ mEventQueue.flush();
+
+ EXPECT_FALSE(mHal->dump(fd, options));
+
+ lseek(memfd, 0, SEEK_SET);
+ char buf[10240] = {};
+ // The dumped info should be empty.
+ read(memfd, buf, sizeof(buf));
+ EXPECT_STREQ("", buf);
+
+ std::this_thread::sleep_for(std::chrono::milliseconds(1000));
+
+ auto events = mEventQueue.flush();
+ // We should get 10 events ideally, but let's be safe here.
+ ASSERT_LE((size_t)5, events.size());
+ int32_t value = 30;
+ for (size_t i = 0; i < 5; i++) {
+ ASSERT_EQ((size_t)1, events[i]->value.floatValues.size());
+ EXPECT_EQ((float)value, events[i]->value.floatValues[0]);
+ value = (value + 20) % 100;
+ }
+
+ // Stop the linear generator.
+ options = {"--debughal", "--genfakedata", "--stoplinear",
+ getPropIdString(VehicleProperty::PERF_VEHICLE_SPEED)};
+ EXPECT_FALSE(mHal->dump(fd, options));
+
+ // The dumped info should be empty.
+ lseek(memfd, 0, SEEK_SET);
+ read(memfd, buf, sizeof(buf));
+ EXPECT_STREQ("", buf);
+
+ close(memfd);
+
+ // Clear existing events.
+ mEventQueue.flush();
+ std::this_thread::sleep_for(std::chrono::milliseconds(500));
+ // There should be no new events generated.
+ EXPECT_EQ((size_t)0, mEventQueue.flush().size());
+}
+
+std::string getTestFilePath(const char* filename) {
+ static std::string baseDir = android::base::GetExecutableDirectory();
+ return baseDir + "/" + filename;
+}
+
+TEST_F(DefaultVhalImplTest, testDebugGenFakeDataJson) {
+ hidl_vec<hidl_string> options = {"--debughal", "--genfakedata", "--startjson",
+ getTestFilePath("prop.json"), "2"};
+ hidl_handle fd = {};
+ int memfd = createMemfd(&fd);
+ // Clear existing events.
+ mEventQueue.flush();
+
+ EXPECT_FALSE(mHal->dump(fd, options));
+
+ lseek(memfd, 0, SEEK_SET);
+ char buf[10240] = {};
+ // The dumped info should be empty.
+ read(memfd, buf, sizeof(buf));
+ EXPECT_STREQ("", buf);
+
+ // wait for some time.
+ std::this_thread::sleep_for(std::chrono::milliseconds(100));
+
+ auto events = mEventQueue.flush();
+ ASSERT_EQ((size_t)8, events.size());
+ // First set of events, we test 1st and the last.
+ EXPECT_EQ((size_t)1, events[0]->value.int32Values.size());
+ EXPECT_EQ(8, events[0]->value.int32Values[0]);
+ EXPECT_EQ((size_t)1, events[3]->value.int32Values.size());
+ EXPECT_EQ(4, events[3]->value.int32Values[0]);
+ // Second set of the same events.
+ EXPECT_EQ((size_t)1, events[4]->value.int32Values.size());
+ EXPECT_EQ(8, events[4]->value.int32Values[0]);
+ EXPECT_EQ((size_t)1, events[7]->value.int32Values.size());
+ EXPECT_EQ(4, events[7]->value.int32Values[0]);
+}
+
+TEST_F(DefaultVhalImplTest, testDebugGenFakeDataKeyPress) {
+ hidl_vec<hidl_string> options = {"--debughal", "--genfakedata", "--keypress", "1", "2"};
+ hidl_handle fd = {};
+ int memfd = createMemfd(&fd);
+ // Clear existing events.
+ mEventQueue.flush();
+
+ EXPECT_FALSE(mHal->dump(fd, options));
+
+ lseek(memfd, 0, SEEK_SET);
+ char buf[10240] = {};
+ // The dumped info should be empty.
+ read(memfd, buf, sizeof(buf));
+ EXPECT_STREQ("", buf);
+
+ auto events = mEventQueue.flush();
+ ASSERT_EQ((size_t)2, events.size());
+ EXPECT_EQ(toInt(VehicleProperty::HW_KEY_INPUT), events[0]->prop);
+ EXPECT_EQ(toInt(VehicleProperty::HW_KEY_INPUT), events[1]->prop);
+ ASSERT_EQ((size_t)3, events[0]->value.int32Values.size());
+ ASSERT_EQ((size_t)3, events[1]->value.int32Values.size());
+ EXPECT_EQ(toInt(VehicleHwKeyInputAction::ACTION_DOWN), events[0]->value.int32Values[0]);
+ EXPECT_EQ(1, events[0]->value.int32Values[1]);
+ EXPECT_EQ(2, events[0]->value.int32Values[2]);
+ EXPECT_EQ(toInt(VehicleHwKeyInputAction::ACTION_UP), events[1]->value.int32Values[0]);
+ EXPECT_EQ(1, events[1]->value.int32Values[1]);
+ EXPECT_EQ(2, events[1]->value.int32Values[2]);
+}
+
} // namespace
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/tests/prop.json b/automotive/vehicle/2.0/default/impl/vhal_v2_0/tests/prop.json
new file mode 100644
index 0000000..2e77a44
--- /dev/null
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/tests/prop.json
@@ -0,0 +1,26 @@
+[
+ {
+ "timestamp": 1000000,
+ "areaId": 0,
+ "value": 8,
+ "prop": 289408000
+ },
+ {
+ "timestamp": 2000000,
+ "areaId": 0,
+ "value": 4,
+ "prop": 289408000
+ },
+ {
+ "timestamp": 3000000,
+ "areaId": 0,
+ "value": 16,
+ "prop": 289408000
+ },
+ {
+ "timestamp": 4000000,
+ "areaId": 0,
+ "value": 4,
+ "prop": 289408000
+ }
+]