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

Commit 56020bc1 authored by Yu Shan's avatar Yu Shan
Browse files

Move emulatedUserHal to default VHAL.

Test: Run on emulator. Verify user hal logic works. unit test.
Bug: 193831021
Change-Id: I9b91205ac11837f31950018f2de12542df85e202
parent 122eea67
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -97,6 +97,7 @@ cc_library_static {
    local_include_dirs: ["common/include/vhal_v2_0"],
    export_include_dirs: ["impl"],
    whole_static_libs: [
        "android.hardware.automotive.vehicle@2.0-emulated-user-hal-lib",
        "android.hardware.automotive.vehicle@2.0-manager-lib",
    ],
    shared_libs: [
@@ -215,8 +216,8 @@ cc_test {
        "android.hardware.automotive.vehicle@2.0-libproto-native",
    ],
    data: [
        ":vhal_test_override_json",
        ":vhal_test_json",
        ":vhal_test_override_json",
    ],
    test_suites: ["general-tests"],
}
+78 −0
Original line number Diff line number Diff line
@@ -89,11 +89,38 @@ DefaultVehicleHal::DefaultVehicleHal(VehiclePropertyStore* propStore, VehicleHal
            });
}

VehicleHal::VehiclePropValuePtr DefaultVehicleHal::getUserHalProp(
        const VehiclePropValue& requestedPropValue, StatusCode* outStatus) {
    auto propId = requestedPropValue.prop;
    ALOGI("get(): getting value for prop %d from User HAL", propId);
    const auto& ret = mEmulatedUserHal.onGetProperty(requestedPropValue);
    VehicleHal::VehiclePropValuePtr v = nullptr;
    if (!ret.ok()) {
        ALOGE("get(): User HAL returned error: %s", ret.error().message().c_str());
        *outStatus = StatusCode(ret.error().code());
    } else {
        auto value = ret.value().get();
        if (value != nullptr) {
            ALOGI("get(): User HAL returned value: %s", toString(*value).c_str());
            v = getValuePool()->obtain(*value);
            *outStatus = StatusCode::OK;
        } else {
            ALOGE("get(): User HAL returned null value");
            *outStatus = StatusCode::INTERNAL_ERROR;
        }
    }
    return addTimestamp(std::move(v));
}

VehicleHal::VehiclePropValuePtr DefaultVehicleHal::get(const VehiclePropValue& requestedPropValue,
                                                       StatusCode* outStatus) {
    auto propId = requestedPropValue.prop;
    ALOGV("get(%d)", propId);

    if (mEmulatedUserHal.isSupported(propId)) {
        return getUserHalProp(requestedPropValue, outStatus);
    }

    VehiclePropValuePtr v = nullptr;
    if (propId == OBD2_FREEZE_FRAME) {
        v = getValuePool()->obtainComplex();
@@ -127,6 +154,36 @@ std::vector<VehiclePropConfig> DefaultVehicleHal::listProperties() {
}

bool DefaultVehicleHal::dump(const hidl_handle& fd, const hidl_vec<hidl_string>& options) {
    int nativeFd = fd->data[0];
    if (nativeFd < 0) {
        ALOGW("Invalid fd from HIDL handle: %d", nativeFd);
        return false;
    }
    if (options.size() > 0) {
        if (options[0] == "--help") {
            std::string buffer;
            buffer += "Emulated user hal usage:\n";
            buffer += mEmulatedUserHal.showDumpHelp();
            buffer += "\n";
            buffer += "VHAL server debug usage:\n";
            buffer += "--debughal: send debug command to VHAL server, see '--debughal --help'\n";
            buffer += "\n";
            dprintf(nativeFd, "%s", buffer.c_str());
            return false;
        } else if (options[0] == kUserHalDumpOption) {
            dprintf(nativeFd, "%s", mEmulatedUserHal.dump("").c_str());
            return false;
        }
    } else {
        // No options, dump the emulated user hal state first and then send command to VHAL server
        // to dump its state.
        std::string buffer;
        buffer += "Emulator user hal state:\n";
        buffer += mEmulatedUserHal.dump("  ");
        buffer += "\n";
        dprintf(nativeFd, "%s", buffer.c_str());
    }

    return mVehicleClient->dump(fd, options);
}

@@ -285,6 +342,23 @@ StatusCode DefaultVehicleHal::checkValueRange(const VehiclePropValue& value,
    return StatusCode::OK;
}

StatusCode DefaultVehicleHal::setUserHalProp(const VehiclePropValue& propValue) {
    ALOGI("onSetProperty(): property %d will be handled by UserHal", propValue.prop);

    const auto& ret = mEmulatedUserHal.onSetProperty(propValue);
    if (!ret.ok()) {
        ALOGE("onSetProperty(): HAL returned error: %s", ret.error().message().c_str());
        return StatusCode(ret.error().code());
    }
    auto updatedValue = ret.value().get();
    if (updatedValue != nullptr) {
        ALOGI("onSetProperty(): updating property returned by HAL: %s",
              toString(*updatedValue).c_str());
        onPropertyValue(*updatedValue, true);
    }
    return StatusCode::OK;
}

StatusCode DefaultVehicleHal::set(const VehiclePropValue& propValue) {
    if (propValue.status != VehiclePropertyStatus::AVAILABLE) {
        // Android side cannot set property status - this value is the
@@ -293,6 +367,10 @@ StatusCode DefaultVehicleHal::set(const VehiclePropValue& propValue) {
        return StatusCode::INVALID_ARG;
    }

    if (mEmulatedUserHal.isSupported(propValue.prop)) {
        return setUserHalProp(propValue);
    }

    std::unordered_set<int32_t> powerProps(std::begin(kHvacPowerProperties),
                                           std::end(kHvacPowerProperties));
    if (powerProps.count(propValue.prop)) {
+7 −0
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@
#include <vhal_v2_0/VehicleHal.h>
#include <vhal_v2_0/VehiclePropertyStore.h>

#include "EmulatedUserHal.h"
#include "VehicleHalClient.h"

namespace android {
@@ -55,6 +56,7 @@ class DefaultVehicleHal : public VehicleHal {
    VehiclePropertyStore* mPropStore;
    RecurrentTimer mRecurrentTimer;
    VehicleHalClient* mVehicleClient;
    EmulatedUserHal mEmulatedUserHal;

    // The callback that would be called when a property value is updated. This function could
    // be extended to handle specific property update event.
@@ -79,6 +81,11 @@ class DefaultVehicleHal : public VehicleHal {
    // Register the heart beat event to be sent every 3s. This is required to inform watch dog that
    // VHAL is alive. Subclasses should always calls this function during onCreate.
    void registerHeartBeatEvent();
    // Get a user HAL property.
    VehiclePropValuePtr getUserHalProp(const VehiclePropValue& requestedPropValue,
                                       StatusCode* outStatus);
    // Set a user HAL property.
    StatusCode setUserHalProp(const VehiclePropValue& propValue);
    // Create a VHAL heart beat property.
    VehicleHal::VehiclePropValuePtr createVhalHeartBeatProp();

+216 −0
Original line number Diff line number Diff line
@@ -1047,4 +1047,220 @@ TEST_F(DefaultVhalImplTest, testClearObd2FreezeFrameOneFrame) {
    ASSERT_EQ(StatusCode::INVALID_ARG, status);
}

TEST_F(DefaultVhalImplTest, testGetUserPropertySetOnly) {
    VehiclePropValue value;
    value.prop = toInt(VehicleProperty::INITIAL_USER_INFO);
    StatusCode status;

    mHal->get(value, &status);

    ASSERT_EQ(StatusCode::INVALID_ARG, status);

    value.prop = toInt(VehicleProperty::SWITCH_USER);

    mHal->get(value, &status);

    ASSERT_EQ(StatusCode::INVALID_ARG, status);

    value.prop = toInt(VehicleProperty::CREATE_USER);

    mHal->get(value, &status);

    ASSERT_EQ(StatusCode::INVALID_ARG, status);

    value.prop = toInt(VehicleProperty::REMOVE_USER);

    mHal->get(value, &status);

    ASSERT_EQ(StatusCode::INVALID_ARG, status);
}

TEST_F(DefaultVhalImplTest, testGetUserIdAssoc) {
    VehiclePropValue value;
    value.prop = toInt(VehicleProperty::USER_IDENTIFICATION_ASSOCIATION);
    StatusCode status;

    mHal->get(value, &status);

    // Default returns NOT_AVAILABLE.
    ASSERT_EQ(StatusCode::NOT_AVAILABLE, status);

    // This is the same example as used in User HAL Emulation doc.
    VehiclePropValue setValue = {
            .prop = toInt(VehicleProperty::USER_IDENTIFICATION_ASSOCIATION),
            .areaId = 1,
            .value.int32Values = {666, 1, 1, 2},
    };

    status = mHal->set(setValue);

    ASSERT_EQ(StatusCode::OK, status);

    auto gotValue = mHal->get(value, &status);

    ASSERT_EQ(StatusCode::OK, status);
    ASSERT_EQ((size_t)4, gotValue->value.int32Values.size());
    EXPECT_EQ(1, gotValue->areaId);
    EXPECT_EQ(666, gotValue->value.int32Values[0]);
    EXPECT_EQ(1, gotValue->value.int32Values[1]);
    EXPECT_EQ(1, gotValue->value.int32Values[2]);
    EXPECT_EQ(2, gotValue->value.int32Values[3]);
    EXPECT_EQ(toInt(VehicleProperty::USER_IDENTIFICATION_ASSOCIATION), gotValue->prop);
}

TEST_F(DefaultVhalImplTest, testSwitchUser) {
    // This is the same example as used in User HAL Emulation doc.
    VehiclePropValue setValue = {
            .prop = toInt(VehicleProperty::SWITCH_USER),
            .areaId = 1,
            .value.int32Values = {666, 3, 2},
    };

    auto status = mHal->set(setValue);

    ASSERT_EQ(StatusCode::OK, status);

    // Simulate a request from Android side.
    setValue = {
            .prop = toInt(VehicleProperty::SWITCH_USER),
            .areaId = 0,
            .value.int32Values = {666, 3},
    };
    // Clear existing events.
    mEventQueue.flush();

    status = mHal->set(setValue);

    ASSERT_EQ(StatusCode::OK, status);

    // Should generate an event for user hal response.
    auto events = mEventQueue.flush();
    ASSERT_EQ((size_t)1, events.size());
    EXPECT_EQ(1, events[0]->areaId);
    EXPECT_EQ(toInt(VehicleProperty::SWITCH_USER), events[0]->prop);
    ASSERT_EQ((size_t)3, events[0]->value.int32Values.size());
    EXPECT_EQ(666, events[0]->value.int32Values[0]);
    EXPECT_EQ(3, events[0]->value.int32Values[1]);
    EXPECT_EQ(2, events[0]->value.int32Values[2]);

    // Try to get switch_user again, should return default value.
    status = mHal->set(setValue);
    ASSERT_EQ(StatusCode::OK, status);

    events = mEventQueue.flush();
    ASSERT_EQ((size_t)1, events.size());
    EXPECT_EQ(0, events[0]->areaId);
    EXPECT_EQ(toInt(VehicleProperty::SWITCH_USER), events[0]->prop);
    ASSERT_EQ((size_t)3, events[0]->value.int32Values.size());
    // Request ID
    EXPECT_EQ(666, events[0]->value.int32Values[0]);
    // VEHICLE_RESPONSE
    EXPECT_EQ(3, events[0]->value.int32Values[1]);
    // SUCCESS
    EXPECT_EQ(1, events[0]->value.int32Values[2]);
}

TEST_F(DefaultVhalImplTest, testCreateUser) {
    // This is the same example as used in User HAL Emulation doc.
    VehiclePropValue setValue = {
            .prop = toInt(VehicleProperty::CREATE_USER),
            .areaId = 1,
            .value.int32Values = {666, 2},
    };

    auto status = mHal->set(setValue);

    ASSERT_EQ(StatusCode::OK, status);

    // Simulate a request from Android side.
    setValue = {
            .prop = toInt(VehicleProperty::CREATE_USER),
            .areaId = 0,
            .value.int32Values = {666},
    };
    // Clear existing events.
    mEventQueue.flush();

    status = mHal->set(setValue);

    ASSERT_EQ(StatusCode::OK, status);

    // Should generate an event for user hal response.
    auto events = mEventQueue.flush();
    ASSERT_EQ((size_t)1, events.size());
    EXPECT_EQ(1, events[0]->areaId);
    EXPECT_EQ(toInt(VehicleProperty::CREATE_USER), events[0]->prop);
    ASSERT_EQ((size_t)2, events[0]->value.int32Values.size());
    EXPECT_EQ(666, events[0]->value.int32Values[0]);
    EXPECT_EQ(2, events[0]->value.int32Values[1]);

    // Try to get create_user again, should return default value.
    status = mHal->set(setValue);
    ASSERT_EQ(StatusCode::OK, status);

    events = mEventQueue.flush();
    ASSERT_EQ((size_t)1, events.size());
    EXPECT_EQ(0, events[0]->areaId);
    EXPECT_EQ(toInt(VehicleProperty::CREATE_USER), events[0]->prop);
    ASSERT_EQ((size_t)2, events[0]->value.int32Values.size());
    // Request ID
    EXPECT_EQ(666, events[0]->value.int32Values[0]);
    // SUCCESS
    EXPECT_EQ(1, events[0]->value.int32Values[1]);
}

TEST_F(DefaultVhalImplTest, testInitialUserInfo) {
    // This is the same example as used in User HAL Emulation doc.
    VehiclePropValue setValue = {
            .prop = toInt(VehicleProperty::INITIAL_USER_INFO),
            .areaId = 1,
            .value.int32Values = {666, 1, 11},
    };

    auto status = mHal->set(setValue);

    ASSERT_EQ(StatusCode::OK, status);

    // Simulate a request from Android side.
    setValue = {
            .prop = toInt(VehicleProperty::INITIAL_USER_INFO),
            .areaId = 0,
            .value.int32Values = {3},
    };
    // Clear existing events.
    mEventQueue.flush();

    status = mHal->set(setValue);

    ASSERT_EQ(StatusCode::OK, status);

    // Should generate an event for user hal response.
    auto events = mEventQueue.flush();
    ASSERT_EQ((size_t)1, events.size());
    EXPECT_EQ(1, events[0]->areaId);
    EXPECT_EQ(toInt(VehicleProperty::INITIAL_USER_INFO), events[0]->prop);
    ASSERT_EQ((size_t)3, events[0]->value.int32Values.size());
    EXPECT_EQ(3, events[0]->value.int32Values[0]);
    EXPECT_EQ(1, events[0]->value.int32Values[1]);
    EXPECT_EQ(11, events[0]->value.int32Values[2]);

    // Try to get create_user again, should return default value.
    status = mHal->set(setValue);
    ASSERT_EQ(StatusCode::OK, status);

    events = mEventQueue.flush();
    ASSERT_EQ((size_t)1, events.size());
    EXPECT_EQ(0, events[0]->areaId);
    EXPECT_EQ(toInt(VehicleProperty::INITIAL_USER_INFO), events[0]->prop);
    ASSERT_EQ((size_t)4, events[0]->value.int32Values.size());
    // Request ID
    EXPECT_EQ(3, events[0]->value.int32Values[0]);
    // ACTION: DEFAULT
    EXPECT_EQ(0, events[0]->value.int32Values[1]);
    // User id: 0
    EXPECT_EQ(0, events[0]->value.int32Values[2]);
    // Flags: 0
    EXPECT_EQ(0, events[0]->value.int32Values[3]);
}

}  // namespace
+31 −0
Original line number Diff line number Diff line
// 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.

// Library used to emulate User HAL behavior through lshal debug requests.
cc_library {
    name: "android.hardware.automotive.vehicle@2.0-emulated-user-hal-lib",
    vendor: true,
    defaults: ["vhal_v2_0_target_defaults"],
    srcs: ["EmulatedUserHal.cpp"],
    shared_libs: [
        "libbase",
        "libutils",
        "libcutils",
    ],
    local_include_dirs: ["include"],
    export_include_dirs: ["include"],
    whole_static_libs: [
        "android.hardware.automotive.vehicle@2.0-user-hal-helper-lib",
    ],
}
Loading