Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 67a276e7 authored by Felipe Leme's avatar Felipe Leme Committed by Automerger Merge Worker
Browse files

Merge "Add a native UserHalHelper library." am: 82120a8c

Original change: https://android-review.googlesource.com/c/platform/hardware/interfaces/+/1425310

Change-Id: I65b9541fee41d161c416b2dd401d962e4fdecf69
parents cbae7c85 82120a8c
Loading
Loading
Loading
Loading
+41 −0
Original line number Diff line number Diff line
// Copyright (C) 2020 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.

// User HAL helper library.
cc_library_static {
    name: "android.hardware.automotive.vehicle@2.0-user-hal-helper-lib",
    defaults: ["vhal_v2_0_defaults"],
    vendor: true,
    host_supported: true,
    srcs: [
        "UserHalHelper.cpp",
    ],
    export_include_dirs: [
        ".",
    ],
}

cc_test {
    name: "android.hardware.automotive.vehicle@2.0-utils-unit-tests",
    defaults: ["vhal_v2_0_defaults"],
    vendor: true,
    srcs: [
        "tests/UserHalHelper_test.cpp",
    ],
    static_libs: [
        "android.hardware.automotive.vehicle@2.0-user-hal-helper-lib",
        "libgmock",
    ],
    test_suites: ["general-tests"],
}
+366 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2020 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.
 */
#define LOG_TAG "UserHalHelper"

#include "UserHalHelper.h"

#include <log/log.h>
#include <utils/SystemClock.h>

namespace android {
namespace hardware {
namespace automotive {
namespace vehicle {
namespace V2_0 {

namespace user_hal_helper {
namespace {

using android::base::Error;
using android::base::Result;

static constexpr const char* kSeparator = "||";
static const size_t kNumFieldsPerUserInfo = 2;
static const size_t kNumFieldsPerSetAssociation = 2;

template <typename T>
Result<T> verifyAndCast(int32_t value) {
    T castValue = static_cast<T>(value);
    const auto iter = hidl_enum_range<T>();
    if (castValue < *iter.begin() || castValue > *std::prev(iter.end())) {
        return Error() << "Value " << value << " not in range [" << toString(*iter.begin()) << ", "
                       << toString(*std::prev(iter.end())) << "]";
    }
    for (const auto& v : hidl_enum_range<T>()) {
        if (castValue == v) {
            return castValue;
        }
    }
    return Error() << "Value " << value << " not in enum values";
}

Result<void> verifyPropValue(const VehiclePropValue& propValue, VehicleProperty vehicleProperty,
                             size_t minInt32Values) {
    auto prop = verifyAndCast<VehicleProperty>(propValue.prop);
    if (!prop.ok()) {
        return Error() << "Invalid vehicle property: " << prop.error();
    }
    if (*prop != vehicleProperty) {
        return Error() << "Mismatching " << toString(vehicleProperty) << " request, received "
                       << toString(*prop) << " property";
    }
    if (propValue.value.int32Values.size() < minInt32Values) {
        return Error() << "Int32Values must have at least " << minInt32Values
                       << " values, received " << propValue.value.int32Values.size();
    }
    return {};
}

Result<void> parseUserInfo(const hidl_vec<int32_t>& int32Values, size_t startPos,
                           UserInfo* userInfo) {
    if (int32Values.size() < startPos + kNumFieldsPerUserInfo) {
        return Error() << "Int32Values must have at least " << startPos + 2 << " values, received "
                       << int32Values.size();
    }
    userInfo->userId = int32Values[startPos];
    auto userFlags = verifyAndCast<UserFlags>(int32Values[startPos + 1]);
    if (!userFlags.ok()) {
        return Error() << "Invalid user flags: " << userFlags.error();
    }
    userInfo->flags = *userFlags;
    return {};
}

Result<void> parseUsersInfo(const hidl_vec<int32_t>& int32Values, size_t startPos,
                            UsersInfo* usersInfo) {
    if (int32Values.size() < startPos + 3) {
        return Error() << "Int32Values must have at least " << startPos + 3 << " values, received "
                       << int32Values.size();
    }
    auto ret = parseUserInfo(int32Values, startPos, &usersInfo->currentUser);
    if (!ret.ok()) {
        return ret;
    }
    usersInfo->numberUsers = int32Values[startPos + 2];
    usersInfo->existingUsers.resize(usersInfo->numberUsers);
    for (size_t i = 0; i < static_cast<size_t>(usersInfo->numberUsers); ++i) {
        ret = parseUserInfo(int32Values, startPos + 3 + (kNumFieldsPerUserInfo * i),
                            &usersInfo->existingUsers[i]);
        if (!ret.ok()) {
            return Error() << "Failed to parse existing user '" << i << "' info: " << ret.error();
        }
    }
    return {};
}

Result<void> parseUserAssociationTypes(
        const hidl_vec<int32_t>& int32Values, size_t startPos, size_t numberAssociationTypes,
        hidl_vec<UserIdentificationAssociationType>* associationTypes) {
    size_t minInt32Values = startPos + numberAssociationTypes;
    if (int32Values.size() < minInt32Values) {
        return Error() << "Int32Values must have at least " << minInt32Values
                       << " values, received " << int32Values.size();
    }
    associationTypes->resize(numberAssociationTypes);
    for (size_t i = 0; i < static_cast<size_t>(numberAssociationTypes); ++i) {
        size_t pos = startPos + i;
        auto type = verifyAndCast<UserIdentificationAssociationType>(int32Values[pos]);
        if (!type.ok()) {
            return Error() << "Invalid association type in query '" << i << "': " << type.error();
        }
        (*associationTypes)[i] = *type;
    }
    return {};
}

Result<void> parseUserAssociations(const hidl_vec<int32_t>& int32Values, size_t startPos,
                                   size_t numberAssociations,
                                   hidl_vec<UserIdentificationSetAssociation>* associations) {
    size_t minInt32Values = startPos + (numberAssociations * kNumFieldsPerSetAssociation);
    if (int32Values.size() < minInt32Values) {
        return Error() << "Int32Values must have at least " << minInt32Values
                       << " values, received " << int32Values.size();
    }
    associations->resize(numberAssociations);
    for (size_t i = 0; i < static_cast<size_t>(numberAssociations); ++i) {
        size_t pos = startPos + (kNumFieldsPerSetAssociation * i);
        auto type = verifyAndCast<UserIdentificationAssociationType>(int32Values[pos]);
        if (!type.ok()) {
            return Error() << "Invalid association type in request '" << i << "': " << type.error();
        }
        (*associations)[i].type = *type;
        auto value = verifyAndCast<UserIdentificationAssociationSetValue>(int32Values[pos + 1]);
        if (!value.ok()) {
            return Error() << "Invalid association set value in request '" << i
                           << "': " << value.error();
        }
        (*associations)[i].value = *value;
    }
    return {};
}

}  // namespace

Result<InitialUserInfoRequest> toInitialUserInfoRequest(const VehiclePropValue& propValue) {
    auto ret = verifyPropValue(propValue, VehicleProperty::INITIAL_USER_INFO, 2);
    if (!ret.ok()) {
        return ret.error();
    }
    InitialUserInfoRequest request;
    request.requestId = propValue.value.int32Values[0];
    auto requestType = verifyAndCast<InitialUserInfoRequestType>(propValue.value.int32Values[1]);
    if (!requestType.ok()) {
        return Error() << "Invalid InitialUserInfoRequestType: " << requestType.error();
    }
    request.requestType = *requestType;
    ret = parseUsersInfo(propValue.value.int32Values, 2, &request.usersInfo);
    if (!ret.ok()) {
        return Error() << "Failed to parse users info: " << ret.error();
    }
    return request;
}

Result<SwitchUserRequest> toSwitchUserRequest(const VehiclePropValue& propValue) {
    auto ret = verifyPropValue(propValue, VehicleProperty::SWITCH_USER, 2);
    if (!ret.ok()) {
        return ret.error();
    }
    SwitchUserRequest request;
    auto messageType = verifyAndCast<SwitchUserMessageType>(propValue.value.int32Values[1]);
    if (!messageType.ok()) {
        return Error() << "Invalid SwitchUserMessageType: " << messageType.error();
    }
    if (*messageType != SwitchUserMessageType::LEGACY_ANDROID_SWITCH &&
        *messageType != SwitchUserMessageType::ANDROID_SWITCH &&
        *messageType != SwitchUserMessageType::ANDROID_POST_SWITCH) {
        return Error() << "Invalid " << toString(*messageType) << " from Android System";
    }
    request.requestId = propValue.value.int32Values[0];
    request.messageType = *messageType;
    ret = parseUserInfo(propValue.value.int32Values, 2, &request.targetUser);
    if (!ret.ok()) {
        return Error() << "Failed to parse target user info: " << ret.error();
    }
    ret = parseUsersInfo(propValue.value.int32Values, 4, &request.usersInfo);
    if (!ret.ok()) {
        return Error() << "Failed to parse users info: " << ret.error();
    }
    return request;
}

Result<CreateUserRequest> toCreateUserRequest(const VehiclePropValue& propValue) {
    auto ret = verifyPropValue(propValue, VehicleProperty::CREATE_USER, 1);
    if (!ret.ok()) {
        return ret.error();
    }
    CreateUserRequest request;
    request.requestId = propValue.value.int32Values[0];
    ret = parseUserInfo(propValue.value.int32Values, 1, &request.newUserInfo);
    if (!ret.ok()) {
        return Error() << "Failed to parse new user info: " << ret.error();
    }
    request.newUserName = propValue.value.stringValue;
    ret = parseUsersInfo(propValue.value.int32Values, 3, &request.usersInfo);
    if (!ret.ok()) {
        return Error() << "Failed to parse users info: " << ret.error();
    }
    return request;
}

Result<RemoveUserRequest> toRemoveUserRequest(const VehiclePropValue& propValue) {
    auto ret = verifyPropValue(propValue, VehicleProperty::REMOVE_USER, 1);
    if (!ret.ok()) {
        return ret.error();
    }
    RemoveUserRequest request;
    request.requestId = propValue.value.int32Values[0];
    ret = parseUserInfo(propValue.value.int32Values, 1, &request.removedUserInfo);
    if (!ret.ok()) {
        return Error() << "Failed to parse removed user info: " << ret.error();
    }
    ret = parseUsersInfo(propValue.value.int32Values, 3, &request.usersInfo);
    if (!ret.ok()) {
        return Error() << "Failed to parse users info: " << ret.error();
    }
    return request;
}

Result<UserIdentificationGetRequest> toUserIdentificationGetRequest(
        const VehiclePropValue& propValue) {
    auto ret = verifyPropValue(propValue, VehicleProperty::USER_IDENTIFICATION_ASSOCIATION, 4);
    if (!ret.ok()) {
        return ret.error();
    }
    UserIdentificationGetRequest request;
    request.requestId = propValue.value.int32Values[0];
    ret = parseUserInfo(propValue.value.int32Values, 1, &request.userInfo);
    if (!ret.ok()) {
        return Error() << "Failed to parse user info: " << ret.error();
    }
    request.numberAssociationTypes = propValue.value.int32Values[3];
    ret = parseUserAssociationTypes(propValue.value.int32Values, 4, request.numberAssociationTypes,
                                    &request.associationTypes);
    if (!ret.ok()) {
        return Error() << "Failed to parse UserIdentificationAssociationType: " << ret.error();
    }
    return request;
}

Result<UserIdentificationSetRequest> toUserIdentificationSetRequest(
        const VehiclePropValue& propValue) {
    auto ret = verifyPropValue(propValue, VehicleProperty::USER_IDENTIFICATION_ASSOCIATION, 4);
    if (!ret.ok()) {
        return ret.error();
    }
    UserIdentificationSetRequest request;
    request.requestId = propValue.value.int32Values[0];
    ret = parseUserInfo(propValue.value.int32Values, 1, &request.userInfo);
    if (!ret.ok()) {
        return Error() << "Failed to parse user info: " << ret.error();
    }
    request.numberAssociations = propValue.value.int32Values[3];
    ret = parseUserAssociations(propValue.value.int32Values, 4, request.numberAssociations,
                                &request.associations);
    if (!ret.ok()) {
        return Error() << "Failed to parse UserIdentificationSetAssociation: " << ret.error();
    }
    return request;
}

std::unique_ptr<VehiclePropValue> toVehiclePropValue(const SwitchUserRequest& request) {
    if (request.messageType != SwitchUserMessageType::VEHICLE_REQUEST) {
        ALOGE("Invalid %s message type %s from HAL", toString(VehicleProperty::SWITCH_USER).c_str(),
              toString(request.messageType).c_str());
        return nullptr;
    }
    auto propValue = std::unique_ptr<VehiclePropValue>(new VehiclePropValue());
    propValue->prop = static_cast<int32_t>(VehicleProperty::SWITCH_USER);
    propValue->timestamp = elapsedRealtimeNano();
    propValue->value.int32Values.resize(3);
    propValue->value.int32Values[0] = static_cast<int32_t>(request.requestId);
    propValue->value.int32Values[1] = static_cast<int32_t>(request.messageType);
    propValue->value.int32Values[2] = static_cast<int32_t>(request.targetUser.userId);
    return propValue;
}

std::unique_ptr<VehiclePropValue> toVehiclePropValue(const InitialUserInfoResponse& response) {
    auto propValue = std::unique_ptr<VehiclePropValue>(new VehiclePropValue());
    propValue->prop = static_cast<int32_t>(VehicleProperty::INITIAL_USER_INFO);
    propValue->timestamp = elapsedRealtimeNano();
    propValue->value.int32Values.resize(4);
    propValue->value.int32Values[0] = static_cast<int32_t>(response.requestId);
    propValue->value.int32Values[1] = static_cast<int32_t>(response.action);
    propValue->value.int32Values[2] = static_cast<int32_t>(response.userToSwitchOrCreate.userId);
    propValue->value.int32Values[3] = static_cast<int32_t>(response.userToSwitchOrCreate.flags);
    propValue->value.stringValue = std::string(response.userLocales) + std::string(kSeparator) +
                                   std::string(response.userNameToCreate);
    return propValue;
}

std::unique_ptr<VehiclePropValue> toVehiclePropValue(const SwitchUserResponse& response) {
    auto propValue = std::unique_ptr<VehiclePropValue>(new VehiclePropValue());
    propValue->prop = static_cast<int32_t>(VehicleProperty::SWITCH_USER);
    propValue->timestamp = elapsedRealtimeNano();
    propValue->value.int32Values.resize(3);
    propValue->value.int32Values[0] = static_cast<int32_t>(response.requestId);
    propValue->value.int32Values[1] = static_cast<int32_t>(response.messageType);
    propValue->value.int32Values[2] = static_cast<int32_t>(response.status);
    if (response.status == SwitchUserStatus::FAILURE) {
        propValue->value.stringValue = response.errorMessage;
    }
    return propValue;
}

std::unique_ptr<VehiclePropValue> toVehiclePropValue(const CreateUserResponse& response) {
    auto propValue = std::unique_ptr<VehiclePropValue>(new VehiclePropValue());
    propValue->prop = static_cast<int32_t>(VehicleProperty::CREATE_USER);
    propValue->timestamp = elapsedRealtimeNano();
    propValue->value.int32Values.resize(2);
    propValue->value.int32Values[0] = static_cast<int32_t>(response.requestId);
    propValue->value.int32Values[1] = static_cast<int32_t>(response.status);
    if (response.status == CreateUserStatus::FAILURE) {
        propValue->value.stringValue = response.errorMessage;
    }
    return propValue;
}

std::unique_ptr<VehiclePropValue> toVehiclePropValue(const UserIdentificationResponse& response) {
    auto propValue = std::unique_ptr<VehiclePropValue>(new VehiclePropValue());
    propValue->prop = static_cast<int32_t>(VehicleProperty::USER_IDENTIFICATION_ASSOCIATION);
    propValue->timestamp = elapsedRealtimeNano();
    propValue->value.int32Values.resize(2 + (response.numberAssociation * 2));
    propValue->value.int32Values[0] = static_cast<int32_t>(response.requestId);
    propValue->value.int32Values[1] = static_cast<int32_t>(response.numberAssociation);
    for (size_t i = 0; i < static_cast<size_t>(response.numberAssociation); ++i) {
        size_t int32ValuesPos = 2 + (2 * i);
        propValue->value.int32Values[int32ValuesPos] =
                static_cast<int32_t>(response.associations[i].type);
        propValue->value.int32Values[int32ValuesPos + 1] =
                static_cast<int32_t>(response.associations[i].value);
    }
    if (!response.errorMessage.empty()) {
        propValue->value.stringValue = response.errorMessage;
    }
    return propValue;
}

}  // namespace user_hal_helper

}  // namespace V2_0
}  // namespace vehicle
}  // namespace automotive
}  // namespace hardware
}  // namespace android
+62 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2020 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 android_hardware_automotive_vehicle_V2_0_impl_UserHalHelper_H_
#define android_hardware_automotive_vehicle_V2_0_impl_UserHalHelper_H_

#include <android-base/result.h>
#include <android/hardware/automotive/vehicle/2.0/types.h>

#include <functional>
#include <memory>

namespace android {
namespace hardware {
namespace automotive {
namespace vehicle {
namespace V2_0 {

namespace user_hal_helper {

// Below functions parse VehiclePropValues to the respective User HAL request structs. On success,
// these functions return the User HAL struct. Otherwise, they return the error.
android::base::Result<InitialUserInfoRequest> toInitialUserInfoRequest(
        const VehiclePropValue& propValue);
android::base::Result<SwitchUserRequest> toSwitchUserRequest(const VehiclePropValue& propValue);
android::base::Result<CreateUserRequest> toCreateUserRequest(const VehiclePropValue& propValue);
android::base::Result<RemoveUserRequest> toRemoveUserRequest(const VehiclePropValue& propValue);
android::base::Result<UserIdentificationGetRequest> toUserIdentificationGetRequest(
        const VehiclePropValue& propValue);
android::base::Result<UserIdentificationSetRequest> toUserIdentificationSetRequest(
        const VehiclePropValue& propValue);

// Below functions convert the User HAL structs to VehiclePropValues. On success, these functions
// return the pointer to VehiclePropValue. Otherwise, they return nullptr.
std::unique_ptr<VehiclePropValue> toVehiclePropValue(const SwitchUserRequest& request);
std::unique_ptr<VehiclePropValue> toVehiclePropValue(const InitialUserInfoResponse& response);
std::unique_ptr<VehiclePropValue> toVehiclePropValue(const SwitchUserResponse& response);
std::unique_ptr<VehiclePropValue> toVehiclePropValue(const CreateUserResponse& response);
std::unique_ptr<VehiclePropValue> toVehiclePropValue(const UserIdentificationResponse& response);

}  // namespace user_hal_helper

}  // namespace V2_0
}  // namespace vehicle
}  // namespace automotive
}  // namespace hardware
}  // namespace android

#endif  // android_hardware_automotive_vehicle_V2_0_impl_UserHalHelper_H_
+666 −0

File added.

Preview size limit exceeded, changes collapsed.