mirror of
https://github.com/Evolution-X/hardware_interfaces
synced 2026-02-02 12:55:23 +00:00
Implemented INITIAL_USER_INFO.
This property 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,
so the following scenarios can be tested:
- property timeout
- HAL response using a different request id
- user switch
- user creation
Bug: 146207078
Test: manual tests with lshal and a modified CarServiceHelper
Test: atest android.hardware.automotive.vehicle@2.0-manager-unit-tests \
android.hardware.automotive.vehicle@2.0-default-impl-unit-tests
Change-Id: Ia5be62c8b19a168c0c6da5307169fc14bf3069c9
This commit is contained in:
@@ -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...
|
||||
@@ -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 {
|
||||
@@ -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];
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -261,6 +264,8 @@ StatusCode EmulatedVehicleServer::onSetProperty(const VehiclePropValue& value, b
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case INITIAL_USER_INFO:
|
||||
return onSetInitialUserInfo(value, updateStatus);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -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>();
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user