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

Commit d2115c98 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Moved emulated User HAL capabilities into a library." into rvc-dev

parents c9490155 9c998c07
Loading
Loading
Loading
Loading
+14 −1
Original line number Diff line number Diff line
@@ -75,7 +75,10 @@ cc_library_static {
    ],
    local_include_dirs: ["common/include/vhal_v2_0"],
    export_include_dirs: ["impl"],
    whole_static_libs: ["android.hardware.automotive.vehicle@2.0-manager-lib"],
    whole_static_libs: [
        "android.hardware.automotive.vehicle@2.0-emulated-user-hal-lib",
        "android.hardware.automotive.vehicle@2.0-manager-lib",
    ],
    shared_libs: [
        "libbase",
        "libjsoncpp",
@@ -87,6 +90,16 @@ cc_library_static {
    ],
}

// Library used  to emulate User HAL behavior through lshal debug requests.
cc_library_static {
    name: "android.hardware.automotive.vehicle@2.0-emulated-user-hal-lib",
    vendor: true,
    defaults: ["vhal_v2_0_defaults"],
    srcs: [
        "impl/vhal_v2_0/EmulatedUserHal.cpp",
    ],
}

cc_test {
    name: "android.hardware.automotive.vehicle@2.0-manager-unit-tests",
    vendor: true,
+0 −2
Original line number Diff line number Diff line
@@ -79,8 +79,6 @@ 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;
constexpr int SWITCH_USER = (int)VehicleProperty::SWITCH_USER;

/**
 * This property is used for test purpose to generate fake events. Here is the test package that
+186 −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 "EmulatedUserHal"

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

#include "EmulatedUserHal.h"

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

namespace impl {

constexpr int INITIAL_USER_INFO = static_cast<int>(VehicleProperty::INITIAL_USER_INFO);
constexpr int SWITCH_USER = static_cast<int>(VehicleProperty::SWITCH_USER);

bool EmulatedUserHal::isSupported(int32_t prop) {
    switch (prop) {
        case INITIAL_USER_INFO:
        case SWITCH_USER:
            return true;
        default:
            return false;
    }
}

android::base::Result<std::unique_ptr<VehiclePropValue>> EmulatedUserHal::onSetProperty(
        const VehiclePropValue& value) {
    ALOGV("onSetProperty(): %s", toString(value).c_str());

    switch (value.prop) {
        case INITIAL_USER_INFO:
            return onSetInitialUserInfoResponse(value);
        case SWITCH_USER:
            return onSetSwitchUserResponse(value);
        default:
            return android::base::Error(static_cast<int>(StatusCode::INVALID_ARG))
                   << "Unsupported property: " << toString(value);
    }
}

android::base::Result<std::unique_ptr<VehiclePropValue>>
EmulatedUserHal::onSetInitialUserInfoResponse(const VehiclePropValue& value) {
    if (value.value.int32Values.size() == 0) {
        ALOGE("set(INITIAL_USER_INFO): no int32values, ignoring it: %s", toString(value).c_str());
        return android::base::Error(static_cast<int>(StatusCode::INVALID_ARG))
               << "no int32values on " << toString(value);
    }

    if (value.areaId != 0) {
        ALOGD("set(INITIAL_USER_INFO) called from lshal; storing it: %s", toString(value).c_str());
        mInitialUserResponseFromCmd.reset(new VehiclePropValue(value));
        return {};
    }

    ALOGD("set(INITIAL_USER_INFO) called from Android: %s", toString(value).c_str());

    int32_t requestId = value.value.int32Values[0];
    if (mInitialUserResponseFromCmd != nullptr) {
        ALOGI("replying INITIAL_USER_INFO with lshal value:  %s",
              toString(*mInitialUserResponseFromCmd).c_str());
        return sendUserHalResponse(std::move(mInitialUserResponseFromCmd), requestId);
    }

    // Returns default response
    auto updatedValue = std::unique_ptr<VehiclePropValue>(new VehiclePropValue);
    updatedValue->prop = INITIAL_USER_INFO;
    updatedValue->timestamp = elapsedRealtimeNano();
    updatedValue->value.int32Values.resize(2);
    updatedValue->value.int32Values[0] = requestId;
    updatedValue->value.int32Values[1] = (int32_t)InitialUserInfoResponseAction::DEFAULT;

    ALOGI("no lshal response; replying with InitialUserInfoResponseAction::DEFAULT: %s",
          toString(*updatedValue).c_str());

    return updatedValue;
}

android::base::Result<std::unique_ptr<VehiclePropValue>> EmulatedUserHal::onSetSwitchUserResponse(
        const VehiclePropValue& value) {
    if (value.value.int32Values.size() == 0) {
        ALOGE("set(SWITCH_USER): no int32values, ignoring it: %s", toString(value).c_str());
        return android::base::Error(static_cast<int>(StatusCode::INVALID_ARG))
               << "no int32values on " << toString(value);
    }

    if (value.areaId != 0) {
        ALOGD("set(SWITCH_USER) called from lshal; storing it: %s", toString(value).c_str());
        mSwitchUserResponseFromCmd.reset(new VehiclePropValue(value));
        return {};
    }
    ALOGD("set(SWITCH_USER) called from Android: %s", toString(value).c_str());

    int32_t requestId = value.value.int32Values[0];
    if (mSwitchUserResponseFromCmd != nullptr) {
        ALOGI("replying SWITCH_USER with lshal value:  %s",
              toString(*mSwitchUserResponseFromCmd).c_str());
        return sendUserHalResponse(std::move(mSwitchUserResponseFromCmd), requestId);
    }

    // Returns default response
    auto updatedValue = std::unique_ptr<VehiclePropValue>(new VehiclePropValue);
    updatedValue->prop = SWITCH_USER;
    updatedValue->timestamp = elapsedRealtimeNano();
    updatedValue->value.int32Values.resize(3);
    updatedValue->value.int32Values[0] = requestId;
    updatedValue->value.int32Values[1] = (int32_t)SwitchUserMessageType::VEHICLE_RESPONSE;
    updatedValue->value.int32Values[2] = (int32_t)SwitchUserStatus::SUCCESS;

    ALOGI("no lshal response; replying with VEHICLE_RESPONSE / SUCCESS: %s",
          toString(*updatedValue).c_str());

    return updatedValue;
}

android::base::Result<std::unique_ptr<VehiclePropValue>> EmulatedUserHal::sendUserHalResponse(
        std::unique_ptr<VehiclePropValue> response, int32_t requestId) {
    switch (response->areaId) {
        case 1:
            ALOGD("returning response with right request id");
            response->value.int32Values[0] = requestId;
            break;
        case 2:
            ALOGD("returning response with wrong request id");
            response->value.int32Values[0] = -requestId;
            break;
        case 3:
            ALOGD("not generating a property change event because of lshal prop: %s",
                  toString(*response).c_str());
            return android::base::Error(static_cast<int>(StatusCode::NOT_AVAILABLE))
                   << "not generating a property change event because of lshal prop: "
                   << toString(*response);
        default:
            ALOGE("invalid action on lshal response: %s", toString(*response).c_str());
            return android::base::Error(static_cast<int>(StatusCode::INTERNAL_ERROR))
                   << "invalid action on lshal response: " << toString(*response);
    }

    ALOGD("updating property to: %s", toString(*response).c_str());

    return response;
}

void EmulatedUserHal::showDumpHelp(int fd) {
    dprintf(fd, "%s: dumps state used for user management\n", kUserHalDumpOption);
}

void EmulatedUserHal::dump(int fd, std::string indent) {
    if (mInitialUserResponseFromCmd != nullptr) {
        dprintf(fd, "%sInitialUserInfo response: %s\n", indent.c_str(),
                toString(*mInitialUserResponseFromCmd).c_str());
    } else {
        dprintf(fd, "%sNo InitialUserInfo response\n", indent.c_str());
    }
    if (mSwitchUserResponseFromCmd != nullptr) {
        dprintf(fd, "%sSwitchUser response: %s\n", indent.c_str(),
                toString(*mSwitchUserResponseFromCmd).c_str());
    } else {
        dprintf(fd, "%sNo SwitchUser response\n", indent.c_str());
    }
}

}  // namespace impl

}  // namespace V2_0
}  // namespace vehicle
}  // namespace automotive
}  // namespace hardware
}  // namespace android
+115 −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_EmulatedUserHal_H_
#define android_hardware_automotive_vehicle_V2_0_impl_EmulatedUserHal_H_

#include <android-base/result.h>

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

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

namespace impl {

constexpr char kUserHalDumpOption[] = "--user-hal";

/**
 * Class used to emulate User HAL behavior through lshal debug requests.
 */
class EmulatedUserHal {
  public:
    EmulatedUserHal() {}

    ~EmulatedUserHal() = default;

    /**
     * Checks if the emulator can handle the property.
     */
    bool isSupported(int32_t prop);

    /**
     * Lets the emulator handle the property.
     *
     * @return updated property and StatusCode
     */
    android::base::Result<std::unique_ptr<VehiclePropValue>> onSetProperty(
            const VehiclePropValue& value);

    /**
     * Shows the User HAL emulation help.
     */
    void showDumpHelp(int fd);

    /**
     * Dump its contents.
     */
    void dump(int fd, std::string indent);

  private:
    /**
     * 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)
     *
     */
    android::base::Result<std::unique_ptr<VehiclePropValue>> onSetInitialUserInfoResponse(
            const VehiclePropValue& value);

    /**
     * Used to emulate SWITCH_USER - see onSetInitialUserInfoResponse() for usage.
     */
    android::base::Result<std::unique_ptr<VehiclePropValue>> onSetSwitchUserResponse(
            const VehiclePropValue& value);

    android::base::Result<std::unique_ptr<VehiclePropValue>> sendUserHalResponse(
            std::unique_ptr<VehiclePropValue> response, int32_t requestId);

    std::unique_ptr<VehiclePropValue> mInitialUserResponseFromCmd;
    std::unique_ptr<VehiclePropValue> mSwitchUserResponseFromCmd;
};

}  // namespace impl

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

#endif  // android_hardware_automotive_vehicle_V2_0_impl_EmulatedUserHal_H_
+4 −22
Original line number Diff line number Diff line
@@ -38,9 +38,6 @@ namespace impl {
class EmulatedPassthroughConnector : public PassthroughConnector {
  public:
    bool onDump(const hidl_handle& fd, const hidl_vec<hidl_string>& options) override;

  private:
    void dumpUserHal(int fd, std::string indent);
};

bool EmulatedPassthroughConnector::onDump(const hidl_handle& handle,
@@ -50,12 +47,12 @@ bool EmulatedPassthroughConnector::onDump(const hidl_handle& handle,
    if (options.size() > 0) {
        if (options[0] == "--help") {
            dprintf(fd, "Emulator-specific usage:\n");
            dprintf(fd, "--user-hal: dumps state used for user management \n");
            mEmulatedUserHal.showDumpHelp(fd);
            dprintf(fd, "\n");
            // Include caller's help options
            return true;
        } else if (options[0] == "--user-hal") {
            dumpUserHal(fd, "");
        } else if (options[0] == kUserHalDumpOption) {
            mEmulatedUserHal.dump(fd, "");
            return false;

        } else {
@@ -65,27 +62,12 @@ bool EmulatedPassthroughConnector::onDump(const hidl_handle& handle,
    }

    dprintf(fd, "Emulator-specific state:\n");
    dumpUserHal(fd, "  ");
    mEmulatedUserHal.dump(fd, "  ");
    dprintf(fd, "\n");

    return true;
}

void EmulatedPassthroughConnector::dumpUserHal(int fd, std::string indent) {
    if (mInitialUserResponseFromCmd != nullptr) {
        dprintf(fd, "%sInitialUserInfo response: %s\n", indent.c_str(),
                toString(*mInitialUserResponseFromCmd).c_str());
    } else {
        dprintf(fd, "%sNo InitialUserInfo response\n", indent.c_str());
    }
    if (mSwitchUserResponseFromCmd != nullptr) {
        dprintf(fd, "%sSwitchUser response: %s\n", indent.c_str(),
                toString(*mSwitchUserResponseFromCmd).c_str());
    } else {
        dprintf(fd, "%sNo SwitchUser response\n", indent.c_str());
    }
}

PassthroughConnectorPtr makeEmulatedPassthroughConnector() {
    return std::make_unique<EmulatedPassthroughConnector>();
}
Loading