Loading automotive/vehicle/2.0/default/common/src/VehicleHalManager.cpp +21 −7 Original line number Diff line number Diff line Loading @@ -28,6 +28,8 @@ #include <hwbinder/IPCThreadState.h> #include <utils/SystemClock.h> #include "VehicleUtils.h" // TODO: figure out how to include private/android_filesystem_config.h instead... Loading Loading @@ -247,10 +249,11 @@ void VehicleHalManager::cmdHelp(int fd) const { dprintf(fd, "--get <PROP1> [PROP2] [PROPN]: dumps the value of specific properties \n"); // TODO: support other formats (int64, float, bytes) dprintf(fd, "--set <PROP> <i|s> <VALUE_1> [<i|s> <VALUE_N>]: sets the value of property PROP, using" " arbitrary number of key/value parameters (i for int32, s for string). Notice that " "the string value can be set just once, while the other can have multiple values " "(so they're used in the respective array)\n"); "--set <PROP> <i|s> <VALUE_1> [<i|s> <VALUE_N>] [a AREA_ID] : sets the value of " "property PROP, using arbitrary number of key/value parameters (i for int32, " "s for string) and an optional area.\n" "Notice that the string value can be set just once, while the other can have multiple " "values (so they're used in the respective array)\n"); } void VehicleHalManager::cmdListAllProperties(int fd) const { Loading Loading @@ -352,13 +355,13 @@ void VehicleHalManager::cmdSetOneProperty(int fd, const hidl_vec<hidl_string>& o VehiclePropValue prop; if (!safelyParseInt(fd, 1, options[1], &prop.prop)) return; prop.timestamp = 0; prop.areaId = 0; // TODO: add option to pass areaId as parameter prop.timestamp = elapsedRealtimeNano(); prop.status = VehiclePropertyStatus::AVAILABLE; // First pass calculate sizes // First pass: calculate sizes int sizeInt32 = 0; int stringIndex = 0; int areaIndex = 0; for (int i = 2, kv = 1; kv <= numberValues; kv++) { // iterate through the kv=1..n key/value pairs, accessing indexes i / i+1 at each step std::string type = options[i]; Loading @@ -374,6 +377,15 @@ void VehicleHalManager::cmdSetOneProperty(int fd, const hidl_vec<hidl_string>& o return; } stringIndex = i; } else if (EqualsIgnoreCase(type, "a")) { if (areaIndex != 0) { dprintf(fd, "defining area value (%s) again at index %d (already defined at %d=%s" ")\n", value.c_str(), i, areaIndex, options[areaIndex + 1].c_str()); return; } areaIndex = i; } else { dprintf(fd, "invalid (%s) type at index %d\n", type.c_str(), i); return; Loading @@ -395,6 +407,8 @@ void VehicleHalManager::cmdSetOneProperty(int fd, const hidl_vec<hidl_string>& o prop.value.int32Values[indexInt32++] = safeInt; } else if (EqualsIgnoreCase(type, "s")) { prop.value.stringValue = value; } else if (EqualsIgnoreCase(type, "a")) { if (!safelyParseInt(fd, valueIndex, value, &prop.areaId)) return; } i += 2; } Loading automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h +11 −0 Original line number Diff line number Diff line Loading @@ -76,6 +76,7 @@ constexpr int WHEEL_FRONT_LEFT = (int)VehicleAreaWheel::LEFT_FRONT; constexpr int WHEEL_FRONT_RIGHT = (int)VehicleAreaWheel::RIGHT_FRONT; constexpr int WHEEL_REAR_LEFT = (int)VehicleAreaWheel::LEFT_REAR; constexpr int WHEEL_REAR_RIGHT = (int)VehicleAreaWheel::RIGHT_REAR; constexpr int INITIAL_USER_INFO = (int)VehicleProperty::INITIAL_USER_INFO; /** * This property is used for test purpose to generate fake events. Here is the test package that Loading Loading @@ -990,6 +991,16 @@ const ConfigDeclaration kVehicleProperties[]{ (int)VehicleVendorPermission::PERMISSION_DEFAULT}, }, .initialValue = {.int32Values = {1}}}, { .config = { .prop = toInt(VehicleProperty::INITIAL_USER_INFO), .access = VehiclePropertyAccess::READ_WRITE, .changeMode = VehiclePropertyChangeMode::ON_CHANGE, }, }, }; } // impl Loading automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.cpp +96 −0 Original line number Diff line number Diff line Loading @@ -13,6 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ #define LOG_TAG "automotive.vehicle@2.0-connector" #include <android-base/logging.h> #include <utils/SystemClock.h> Loading Loading @@ -261,6 +264,8 @@ StatusCode EmulatedVehicleServer::onSetProperty(const VehiclePropValue& value, b break; } break; case INITIAL_USER_INFO: return onSetInitialUserInfo(value, updateStatus); default: break; } Loading @@ -274,6 +279,97 @@ StatusCode EmulatedVehicleServer::onSetProperty(const VehiclePropValue& value, b return StatusCode::OK; } /** * INITIAL_USER_INFO is called by Android when it starts, and it's expecting a property change * indicating what the initial user should be. * * During normal circumstances, the emulator will reply right away, passing a response if * InitialUserInfoResponseAction::DEFAULT (so Android could use its own logic to decide which user * to boot). * * But during development / testing, the behavior can be changed using lshal dump, which must use * the areaId to indicate what should happen next. * * So, the behavior of set(INITIAL_USER_INFO) is: * * - if it has an areaId, store the property into mInitialUserResponseFromCmd (as it was called by * lshal). * - else if mInitialUserResponseFromCmd is not set, return a response with the same request id and * InitialUserInfoResponseAction::DEFAULT * - else the behavior is defined by the areaId on mInitialUserResponseFromCmd: * - if it's 1, reply with mInitialUserResponseFromCmd and the right request id * - if it's 2, reply with mInitialUserResponseFromCmd but a wrong request id (so Android can test * this error scenario) * - if it's 3, then don't send a property change (so Android can emulate a timeout) * */ StatusCode EmulatedVehicleServer::onSetInitialUserInfo(const VehiclePropValue& value, bool updateStatus) { // TODO: LOG calls below might be more suited to be DEBUG, but those are not being logged // (even when explicitly calling setprop log.tag. As this class should be using ALOG instead of // LOG, it's not worth investigating why... if (value.areaId != 0) { LOG(INFO) << "set(INITIAL_USER_INFO) called from lshal; storing it: " << toString(value); mInitialUserResponseFromCmd.reset(new VehiclePropValue(value)); return StatusCode::OK; } LOG(INFO) << "set(INITIAL_USER_INFO) called from Android: " << toString(value); if (value.value.int32Values.size() == 0) { LOG(ERROR) << "invalid request (no requestId): " << toString(value); return StatusCode::INVALID_ARG; } int32_t requestId = value.value.int32Values[0]; // Create the update property and set common values auto updatedValue = createVehiclePropValue(VehiclePropertyType::MIXED, 0); updatedValue->prop = INITIAL_USER_INFO; updatedValue->timestamp = elapsedRealtimeNano(); if (mInitialUserResponseFromCmd == nullptr) { updatedValue->value.int32Values.resize(2); updatedValue->value.int32Values[0] = requestId; updatedValue->value.int32Values[1] = (int32_t)InitialUserInfoResponseAction::DEFAULT; LOG(INFO) << "no lshal response; returning InitialUserInfoResponseAction::DEFAULT: " << toString(*updatedValue); onPropertyValueFromCar(*updatedValue, updateStatus); return StatusCode::OK; } // mInitialUserResponseFromCmd is used for just one request std::unique_ptr<VehiclePropValue> response = std::move(mInitialUserResponseFromCmd); // TODO(b/138709788): rather than populate the raw values directly, it should use the // libraries that convert a InitialUserInfoResponse into a VehiclePropValue) switch (response->areaId) { case 1: LOG(INFO) << "returning response with right request id"; *updatedValue = *response; updatedValue->areaId = 0; updatedValue->value.int32Values[0] = requestId; break; case 2: LOG(INFO) << "returning response with wrong request id"; *updatedValue = *response; updatedValue->areaId = 0; updatedValue->value.int32Values[0] = -requestId; break; case 3: LOG(INFO) << "not generating a property change event because of lshal prop: " << toString(*response); return StatusCode::OK; default: LOG(ERROR) << "invalid action on lshal response: " << toString(*response); return StatusCode::INTERNAL_ERROR; } LOG(INFO) << "updating property to: " << toString(*updatedValue); onPropertyValueFromCar(*updatedValue, updateStatus); return StatusCode::OK; } EmulatedPassthroughConnectorPtr makeEmulatedPassthroughConnector() { return std::make_unique<EmulatedPassthroughConnector>(); } Loading automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.h +4 −0 Original line number Diff line number Diff line Loading @@ -77,6 +77,10 @@ class EmulatedVehicleServer : public IVehicleServer { std::bind(&EmulatedVehicleServer::onFakeValueGenerated, this, std::placeholders::_1)}; VehiclePropValuePool* mValuePool{nullptr}; // TODO(b/146207078): it might be clearer to move members below to an EmulatedUserHal class std::unique_ptr<VehiclePropValue> mInitialUserResponseFromCmd; StatusCode onSetInitialUserInfo(const VehiclePropValue& value, bool updateStatus); }; // Helper functions Loading Loading
automotive/vehicle/2.0/default/common/src/VehicleHalManager.cpp +21 −7 Original line number Diff line number Diff line Loading @@ -28,6 +28,8 @@ #include <hwbinder/IPCThreadState.h> #include <utils/SystemClock.h> #include "VehicleUtils.h" // TODO: figure out how to include private/android_filesystem_config.h instead... Loading Loading @@ -247,10 +249,11 @@ void VehicleHalManager::cmdHelp(int fd) const { dprintf(fd, "--get <PROP1> [PROP2] [PROPN]: dumps the value of specific properties \n"); // TODO: support other formats (int64, float, bytes) dprintf(fd, "--set <PROP> <i|s> <VALUE_1> [<i|s> <VALUE_N>]: sets the value of property PROP, using" " arbitrary number of key/value parameters (i for int32, s for string). Notice that " "the string value can be set just once, while the other can have multiple values " "(so they're used in the respective array)\n"); "--set <PROP> <i|s> <VALUE_1> [<i|s> <VALUE_N>] [a AREA_ID] : sets the value of " "property PROP, using arbitrary number of key/value parameters (i for int32, " "s for string) and an optional area.\n" "Notice that the string value can be set just once, while the other can have multiple " "values (so they're used in the respective array)\n"); } void VehicleHalManager::cmdListAllProperties(int fd) const { Loading Loading @@ -352,13 +355,13 @@ void VehicleHalManager::cmdSetOneProperty(int fd, const hidl_vec<hidl_string>& o VehiclePropValue prop; if (!safelyParseInt(fd, 1, options[1], &prop.prop)) return; prop.timestamp = 0; prop.areaId = 0; // TODO: add option to pass areaId as parameter prop.timestamp = elapsedRealtimeNano(); prop.status = VehiclePropertyStatus::AVAILABLE; // First pass calculate sizes // First pass: calculate sizes int sizeInt32 = 0; int stringIndex = 0; int areaIndex = 0; for (int i = 2, kv = 1; kv <= numberValues; kv++) { // iterate through the kv=1..n key/value pairs, accessing indexes i / i+1 at each step std::string type = options[i]; Loading @@ -374,6 +377,15 @@ void VehicleHalManager::cmdSetOneProperty(int fd, const hidl_vec<hidl_string>& o return; } stringIndex = i; } else if (EqualsIgnoreCase(type, "a")) { if (areaIndex != 0) { dprintf(fd, "defining area value (%s) again at index %d (already defined at %d=%s" ")\n", value.c_str(), i, areaIndex, options[areaIndex + 1].c_str()); return; } areaIndex = i; } else { dprintf(fd, "invalid (%s) type at index %d\n", type.c_str(), i); return; Loading @@ -395,6 +407,8 @@ void VehicleHalManager::cmdSetOneProperty(int fd, const hidl_vec<hidl_string>& o prop.value.int32Values[indexInt32++] = safeInt; } else if (EqualsIgnoreCase(type, "s")) { prop.value.stringValue = value; } else if (EqualsIgnoreCase(type, "a")) { if (!safelyParseInt(fd, valueIndex, value, &prop.areaId)) return; } i += 2; } Loading
automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h +11 −0 Original line number Diff line number Diff line Loading @@ -76,6 +76,7 @@ constexpr int WHEEL_FRONT_LEFT = (int)VehicleAreaWheel::LEFT_FRONT; constexpr int WHEEL_FRONT_RIGHT = (int)VehicleAreaWheel::RIGHT_FRONT; constexpr int WHEEL_REAR_LEFT = (int)VehicleAreaWheel::LEFT_REAR; constexpr int WHEEL_REAR_RIGHT = (int)VehicleAreaWheel::RIGHT_REAR; constexpr int INITIAL_USER_INFO = (int)VehicleProperty::INITIAL_USER_INFO; /** * This property is used for test purpose to generate fake events. Here is the test package that Loading Loading @@ -990,6 +991,16 @@ const ConfigDeclaration kVehicleProperties[]{ (int)VehicleVendorPermission::PERMISSION_DEFAULT}, }, .initialValue = {.int32Values = {1}}}, { .config = { .prop = toInt(VehicleProperty::INITIAL_USER_INFO), .access = VehiclePropertyAccess::READ_WRITE, .changeMode = VehiclePropertyChangeMode::ON_CHANGE, }, }, }; } // impl Loading
automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.cpp +96 −0 Original line number Diff line number Diff line Loading @@ -13,6 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ #define LOG_TAG "automotive.vehicle@2.0-connector" #include <android-base/logging.h> #include <utils/SystemClock.h> Loading Loading @@ -261,6 +264,8 @@ StatusCode EmulatedVehicleServer::onSetProperty(const VehiclePropValue& value, b break; } break; case INITIAL_USER_INFO: return onSetInitialUserInfo(value, updateStatus); default: break; } Loading @@ -274,6 +279,97 @@ StatusCode EmulatedVehicleServer::onSetProperty(const VehiclePropValue& value, b return StatusCode::OK; } /** * INITIAL_USER_INFO is called by Android when it starts, and it's expecting a property change * indicating what the initial user should be. * * During normal circumstances, the emulator will reply right away, passing a response if * InitialUserInfoResponseAction::DEFAULT (so Android could use its own logic to decide which user * to boot). * * But during development / testing, the behavior can be changed using lshal dump, which must use * the areaId to indicate what should happen next. * * So, the behavior of set(INITIAL_USER_INFO) is: * * - if it has an areaId, store the property into mInitialUserResponseFromCmd (as it was called by * lshal). * - else if mInitialUserResponseFromCmd is not set, return a response with the same request id and * InitialUserInfoResponseAction::DEFAULT * - else the behavior is defined by the areaId on mInitialUserResponseFromCmd: * - if it's 1, reply with mInitialUserResponseFromCmd and the right request id * - if it's 2, reply with mInitialUserResponseFromCmd but a wrong request id (so Android can test * this error scenario) * - if it's 3, then don't send a property change (so Android can emulate a timeout) * */ StatusCode EmulatedVehicleServer::onSetInitialUserInfo(const VehiclePropValue& value, bool updateStatus) { // TODO: LOG calls below might be more suited to be DEBUG, but those are not being logged // (even when explicitly calling setprop log.tag. As this class should be using ALOG instead of // LOG, it's not worth investigating why... if (value.areaId != 0) { LOG(INFO) << "set(INITIAL_USER_INFO) called from lshal; storing it: " << toString(value); mInitialUserResponseFromCmd.reset(new VehiclePropValue(value)); return StatusCode::OK; } LOG(INFO) << "set(INITIAL_USER_INFO) called from Android: " << toString(value); if (value.value.int32Values.size() == 0) { LOG(ERROR) << "invalid request (no requestId): " << toString(value); return StatusCode::INVALID_ARG; } int32_t requestId = value.value.int32Values[0]; // Create the update property and set common values auto updatedValue = createVehiclePropValue(VehiclePropertyType::MIXED, 0); updatedValue->prop = INITIAL_USER_INFO; updatedValue->timestamp = elapsedRealtimeNano(); if (mInitialUserResponseFromCmd == nullptr) { updatedValue->value.int32Values.resize(2); updatedValue->value.int32Values[0] = requestId; updatedValue->value.int32Values[1] = (int32_t)InitialUserInfoResponseAction::DEFAULT; LOG(INFO) << "no lshal response; returning InitialUserInfoResponseAction::DEFAULT: " << toString(*updatedValue); onPropertyValueFromCar(*updatedValue, updateStatus); return StatusCode::OK; } // mInitialUserResponseFromCmd is used for just one request std::unique_ptr<VehiclePropValue> response = std::move(mInitialUserResponseFromCmd); // TODO(b/138709788): rather than populate the raw values directly, it should use the // libraries that convert a InitialUserInfoResponse into a VehiclePropValue) switch (response->areaId) { case 1: LOG(INFO) << "returning response with right request id"; *updatedValue = *response; updatedValue->areaId = 0; updatedValue->value.int32Values[0] = requestId; break; case 2: LOG(INFO) << "returning response with wrong request id"; *updatedValue = *response; updatedValue->areaId = 0; updatedValue->value.int32Values[0] = -requestId; break; case 3: LOG(INFO) << "not generating a property change event because of lshal prop: " << toString(*response); return StatusCode::OK; default: LOG(ERROR) << "invalid action on lshal response: " << toString(*response); return StatusCode::INTERNAL_ERROR; } LOG(INFO) << "updating property to: " << toString(*updatedValue); onPropertyValueFromCar(*updatedValue, updateStatus); return StatusCode::OK; } EmulatedPassthroughConnectorPtr makeEmulatedPassthroughConnector() { return std::make_unique<EmulatedPassthroughConnector>(); } Loading
automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.h +4 −0 Original line number Diff line number Diff line Loading @@ -77,6 +77,10 @@ class EmulatedVehicleServer : public IVehicleServer { std::bind(&EmulatedVehicleServer::onFakeValueGenerated, this, std::placeholders::_1)}; VehiclePropValuePool* mValuePool{nullptr}; // TODO(b/146207078): it might be clearer to move members below to an EmulatedUserHal class std::unique_ptr<VehiclePropValue> mInitialUserResponseFromCmd; StatusCode onSetInitialUserInfo(const VehiclePropValue& value, bool updateStatus); }; // Helper functions Loading