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

Commit 7a723546 authored by Stan Rokita's avatar Stan Rokita
Browse files

MultiHal 2.0 - setOperationMode and init direct channel flags

Implement setOperationMode method of HalProxy object and initialized the
direct channel flag for the sensors list. Also create some unit tests to
test both of these new additions in HalProxy_test.cpp.

Bug: 136511617
Test: Tested using unit tests and tested on device with both fake
      subhals

Change-Id: I4e39ca0e94b3e109706d628612d1db9c98aca053
parent dc7a8e78
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -45,6 +45,7 @@ cc_binary {
    ],
    init_rc: ["android.hardware.sensors@2.0-service-multihal.rc"],
    vintf_fragments: ["android.hardware.sensors@2.0-multihal.xml"],
    cflags: ["-DLOG_TAG=\"SensorsMultiHal\""],
}

cc_library_headers {
+44 −11
Original line number Diff line number Diff line
@@ -69,8 +69,8 @@ class SensorsCallbackProxy : public ISensorsCallback {
};

HalProxy::HalProxy() {
    const char* kMultiHalConfigFilePath = "/vendor/etc/sensors/hals.conf";
    initializeSubHalListFromConfigFile(kMultiHalConfigFilePath);
    const char* kMultiHalConfigFile = "/vendor/etc/sensors/hals.conf";
    initializeSubHalListFromConfigFile(kMultiHalConfigFile);
    initializeSensorList();
}

@@ -88,9 +88,27 @@ Return<void> HalProxy::getSensorsList(getSensorsList_cb _hidl_cb) {
    return Void();
}

Return<Result> HalProxy::setOperationMode(OperationMode /* mode */) {
    // TODO: Proxy API call to all sub-HALs and return appropriate result.
    return Result::INVALID_OPERATION;
Return<Result> HalProxy::setOperationMode(OperationMode mode) {
    Result result = Result::OK;
    size_t subHalIndex;
    for (subHalIndex = 0; subHalIndex < mSubHalList.size(); subHalIndex++) {
        ISensorsSubHal* subHal = mSubHalList[subHalIndex];
        result = subHal->setOperationMode(mode);
        if (result != Result::OK) {
            ALOGE("setOperationMode failed for SubHal: %s", subHal->getName().c_str());
            break;
        }
    }
    if (result != Result::OK) {
        // Reset the subhal operation modes that have been flipped
        for (size_t i = 0; i < subHalIndex; i++) {
            ISensorsSubHal* subHal = mSubHalList[i];
            subHal->setOperationMode(mCurrentOperationMode);
        }
    } else {
        mCurrentOperationMode = mode;
    }
    return result;
}

Return<Result> HalProxy::activate(int32_t sensorHandle, bool enabled) {
@@ -190,18 +208,18 @@ Return<void> HalProxy::onDynamicSensorsDisconnected(
void HalProxy::initializeSubHalListFromConfigFile(const char* configFileName) {
    std::ifstream subHalConfigStream(configFileName);
    if (!subHalConfigStream) {
        LOG_FATAL("Failed to load subHal config file: %s", configFileName);
        ALOGE("Failed to load subHal config file: %s", configFileName);
    } else {
        std::string subHalLibraryFile;
        while (subHalConfigStream >> subHalLibraryFile) {
            void* handle = dlopen(subHalLibraryFile.c_str(), RTLD_NOW);
            if (handle == nullptr) {
                LOG_FATAL("dlopen failed for library: %s", subHalLibraryFile.c_str());
                ALOGE("dlopen failed for library: %s", subHalLibraryFile.c_str());
            } else {
                SensorsHalGetSubHalFunc* sensorsHalGetSubHalPtr =
                        (SensorsHalGetSubHalFunc*)dlsym(handle, "sensorsHalGetSubHal");
                if (sensorsHalGetSubHalPtr == nullptr) {
                    LOG_FATAL("Failed to locate sensorsHalGetSubHal function for library: %s",
                    ALOGE("Failed to locate sensorsHalGetSubHal function for library: %s",
                          subHalLibraryFile.c_str());
                } else {
                    std::function<SensorsHalGetSubHalFunc> sensorsHalGetSubHal =
@@ -209,7 +227,7 @@ void HalProxy::initializeSubHalListFromConfigFile(const char* configFileName) {
                    uint32_t version;
                    ISensorsSubHal* subHal = sensorsHalGetSubHal(&version);
                    if (version != SUB_HAL_2_0_VERSION) {
                        LOG_FATAL("SubHal version was not 2.0 for library: %s",
                        ALOGE("SubHal version was not 2.0 for library: %s",
                              subHalLibraryFile.c_str());
                    } else {
                        ALOGV("Loaded SubHal from library: %s", subHalLibraryFile.c_str());
@@ -231,6 +249,7 @@ void HalProxy::initializeSensorList() {
                } else {
                    ALOGV("Loaded sensor: %s", sensor.name.c_str());
                    sensor.sensorHandle |= (subHalIndex << 24);
                    setDirectChannelFlags(&sensor, subHal);
                    mSensorList.push_back(sensor);
                }
            }
@@ -241,6 +260,20 @@ void HalProxy::initializeSensorList() {
    }
}

void HalProxy::setDirectChannelFlags(SensorInfo* sensorInfo, ISensorsSubHal* subHal) {
    bool sensorSupportsDirectChannel =
            (sensorInfo->flags & (V1_0::SensorFlagBits::MASK_DIRECT_REPORT |
                                  V1_0::SensorFlagBits::MASK_DIRECT_CHANNEL)) != 0;
    if (mDirectChannelSubHal == nullptr && sensorSupportsDirectChannel) {
        mDirectChannelSubHal = subHal;
    } else if (mDirectChannelSubHal != nullptr && subHal != mDirectChannelSubHal) {
        // disable direct channel capability for sensors in subHals that are not
        // the only one we will enable
        sensorInfo->flags &= ~(V1_0::SensorFlagBits::MASK_DIRECT_REPORT |
                               V1_0::SensorFlagBits::MASK_DIRECT_CHANNEL);
    }
}

ISensorsSubHal* HalProxy::getSubHalForSensorHandle(uint32_t sensorHandle) {
    return mSubHalList[static_cast<size_t>(sensorHandle >> 24)];
}
+18 −1
Original line number Diff line number Diff line
@@ -125,10 +125,16 @@ class HalProxy : public ISensors {
     * well as the modified sensor handle for the framework.
     *
     * The subhal index is encoded in the first byte of the sensor handle and
     * the remaining bytes are generated by the subhal.
     * the remaining bytes are generated by the subhal to identify the sensor.
     */
    std::vector<SensorInfo> mSensorList;

    //! The current operation mode for all subhals.
    OperationMode mCurrentOperationMode = OperationMode::NORMAL;

    //! The single subHal that supports directChannel reporting.
    ISensorsSubHal* mDirectChannelSubHal = nullptr;

    /**
     * Initialize the list of SubHal objects in mSubHalList by reading from dynamic libraries
     * listed in a config file.
@@ -141,6 +147,17 @@ class HalProxy : public ISensors {
     */
    void initializeSensorList();

    /**
     * Clear direct channel flags if the HalProxy has already chosen a subhal as its direct channel
     * subhal. Set the directChannelSubHal pointer to the subHal passed in if this is the first
     * direct channel enabled sensor seen.
     *
     * @param sensorInfo The SensorInfo object that may be altered to have direct channel support
     *    disabled.
     * @param subHal The subhal pointer that the current sensorInfo object came from.
     */
    void setDirectChannelFlags(SensorInfo* sensorInfo, ISensorsSubHal* subHal);

    /*
     * Get the subhal pointer which can be found by indexing into the mSubHalList vector
     * using the index from the first byte of sensorHandle.
+0 −2
Original line number Diff line number Diff line
@@ -14,8 +14,6 @@
 * limitations under the License.
 */

#define LOG_TAG "android.hardware.sensors@2.0-service"

#include <android/hardware/sensors/2.0/ISensors.h>
#include <hidl/HidlTransportSupport.h>
#include <log/log.h>
+109 −10
Original line number Diff line number Diff line
@@ -15,33 +15,56 @@

#include <gtest/gtest.h>

#include <android/hardware/sensors/2.0/types.h>

#include "HalProxy.h"
#include "SensorsSubHal.h"

#include <vector>

namespace {

using ::android::hardware::sensors::V1_0::SensorFlagBits;
using ::android::hardware::sensors::V1_0::SensorInfo;
using ::android::hardware::sensors::V1_0::SensorType;
using ::android::hardware::sensors::V2_0::implementation::HalProxy;
using ::android::hardware::sensors::V2_0::subhal::implementation::AllSensorsSubHal;
using ::android::hardware::sensors::V2_0::subhal::implementation::
        AllSupportDirectChannelSensorsSubHal;
using ::android::hardware::sensors::V2_0::subhal::implementation::ContinuousSensorsSubHal;
using ::android::hardware::sensors::V2_0::subhal::implementation::
        DoesNotSupportDirectChannelSensorsSubHal;
using ::android::hardware::sensors::V2_0::subhal::implementation::OnChangeSensorsSubHal;
using ::android::hardware::sensors::V2_0::subhal::implementation::SensorsSubHal;

// TODO: Add more interesting tests such as
//     - verify setOperationMode invokes all subhals
//     - verify if a subhal fails to change operation mode, that state is reset properly
//     - Available sensors are obtained during initialization
//
// You can run this suite using "atest android.hardware.sensors@2.0-halproxy-unit-tests".
//
// See https://source.android.com/compatibility/tests/development/native-func-e2e.md for more info
// on how tests are set up and for information on the gtest framework itself.
using ::android::hardware::sensors::V2_0::subhal::implementation::
        SetOperationModeFailingSensorsSubHal;

// Helper declarations follow

/**
 * Tests that for each SensorInfo object from a proxy getSensorsList call each corresponding
 * object from a subhal getSensorsList call has the same type and its last 3 bytes are the
 * same for sensorHandle field.
 *
 * @param proxySensorsList The list of SensorInfo objects from the proxy.getSensorsList callback.
 * @param subHalSenosrsList The list of SensorInfo objects from the subHal.getSensorsList callback.
 */
void testSensorsListFromProxyAndSubHal(const std::vector<SensorInfo>& proxySensorsList,
                                       const std::vector<SensorInfo>& subHalSensorsList);

/**
 * Tests that there is exactly one subhal that allows its sensors to have direct channel enabled.
 * Therefore, all SensorInfo objects that are not from the enabled subhal should be disabled for
 * direct channel.
 *
 * @param sensorsList The SensorInfo object list from proxy.getSensorsList call.
 * @param enabledSubHalIndex The index of the subhal in the halproxy that is expected to be
 *     enabled.
 */
void testSensorsListForOneDirectChannelEnabledSubHal(const std::vector<SensorInfo>& sensorsList,
                                                     size_t enabledSubHalIndex);

// Tests follow
TEST(HalProxyTest, GetSensorsListOneSubHalTest) {
    AllSensorsSubHal subHal;
@@ -76,6 +99,63 @@ TEST(HalProxyTest, GetSensorsListTwoSubHalTest) {
    testSensorsListFromProxyAndSubHal(proxySensorsList, combinedSubHalSensorsList);
}

TEST(HalProxyTest, SetOperationModeTwoSubHalSuccessTest) {
    ContinuousSensorsSubHal subHal1;
    OnChangeSensorsSubHal subHal2;

    std::vector<ISensorsSubHal*> fakeSubHals{&subHal1, &subHal2};
    HalProxy proxy(fakeSubHals);

    EXPECT_EQ(subHal1.getOperationMode(), OperationMode::NORMAL);
    EXPECT_EQ(subHal2.getOperationMode(), OperationMode::NORMAL);

    Result result = proxy.setOperationMode(OperationMode::DATA_INJECTION);

    EXPECT_EQ(result, Result::OK);
    EXPECT_EQ(subHal1.getOperationMode(), OperationMode::DATA_INJECTION);
    EXPECT_EQ(subHal2.getOperationMode(), OperationMode::DATA_INJECTION);
}

TEST(HalProxyTest, SetOperationModeTwoSubHalFailTest) {
    AllSensorsSubHal subHal1;
    SetOperationModeFailingSensorsSubHal subHal2;

    std::vector<ISensorsSubHal*> fakeSubHals{&subHal1, &subHal2};
    HalProxy proxy(fakeSubHals);

    EXPECT_EQ(subHal1.getOperationMode(), OperationMode::NORMAL);
    EXPECT_EQ(subHal2.getOperationMode(), OperationMode::NORMAL);

    Result result = proxy.setOperationMode(OperationMode::DATA_INJECTION);

    EXPECT_NE(result, Result::OK);
    EXPECT_EQ(subHal1.getOperationMode(), OperationMode::NORMAL);
    EXPECT_EQ(subHal2.getOperationMode(), OperationMode::NORMAL);
}

TEST(HalProxyTest, InitDirectChannelTwoSubHalsUnitTest) {
    AllSupportDirectChannelSensorsSubHal subHal1;
    AllSupportDirectChannelSensorsSubHal subHal2;

    std::vector<ISensorsSubHal*> fakeSubHals{&subHal1, &subHal2};
    HalProxy proxy(fakeSubHals);

    proxy.getSensorsList([&](const auto& sensorsList) {
        testSensorsListForOneDirectChannelEnabledSubHal(sensorsList, 0);
    });
}

TEST(HalProxyTest, InitDirectChannelThreeSubHalsUnitTest) {
    DoesNotSupportDirectChannelSensorsSubHal subHal1;
    AllSupportDirectChannelSensorsSubHal subHal2, subHal3;
    std::vector<ISensorsSubHal*> fakeSubHals{&subHal1, &subHal2, &subHal3};
    HalProxy proxy(fakeSubHals);

    proxy.getSensorsList([&](const auto& sensorsList) {
        testSensorsListForOneDirectChannelEnabledSubHal(sensorsList, 1);
    });
}

// Helper implementations follow
void testSensorsListFromProxyAndSubHal(const std::vector<SensorInfo>& proxySensorsList,
                                       const std::vector<SensorInfo>& subHalSensorsList) {
@@ -89,3 +169,22 @@ void testSensorsListFromProxyAndSubHal(const std::vector<SensorInfo>& proxySenso
        EXPECT_EQ(proxySensor.sensorHandle & 0x00FFFFFF, subHalSensor.sensorHandle);
    }
}

void testSensorsListForOneDirectChannelEnabledSubHal(const std::vector<SensorInfo>& sensorsList,
                                                     size_t enabledSubHalIndex) {
    for (const SensorInfo& sensor : sensorsList) {
        size_t subHalIndex = static_cast<size_t>(sensor.sensorHandle >> 24);
        if (subHalIndex == enabledSubHalIndex) {
            // First subhal should have been picked as the direct channel subhal
            // and so have direct channel enabled on all of its sensors
            EXPECT_NE(sensor.flags & SensorFlagBits::MASK_DIRECT_REPORT, 0);
            EXPECT_NE(sensor.flags & SensorFlagBits::MASK_DIRECT_CHANNEL, 0);
        } else {
            // All other subhals should have direct channel disabled for all sensors
            EXPECT_EQ(sensor.flags & SensorFlagBits::MASK_DIRECT_REPORT, 0);
            EXPECT_EQ(sensor.flags & SensorFlagBits::MASK_DIRECT_CHANNEL, 0);
        }
    }
}

}  // namespace
Loading