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

Commit 012f4e7d authored by Grace Cheng's avatar Grace Cheng Committed by Android (Google) Code Review
Browse files

Merge "Implements AIDL VTS direct channel tests"

parents eac016a7 629b3a4c
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -34,6 +34,7 @@ cc_test {
    shared_libs: [
        "libbinder",
        "libbinder_ndk",
        "libvndksupport",
        "libfmq",
        "android.hardware.common-V2-ndk",
        "android.hardware.common.fmq-V1-ndk",
@@ -41,6 +42,7 @@ cc_test {
    static_libs: [
        "android.hardware.sensors-V1-ndk",
        "VtsHalSensorsTargetTestUtils",
        "libaidlcommonsupport",
    ],
    test_suites: [
        "general-tests",
+218 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2022 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_SENSORS_AIDL_TEST_SHARED_MEMORY_H
#define ANDROID_SENSORS_AIDL_TEST_SHARED_MEMORY_H

#include "sensors-vts-utils/GrallocWrapper.h"

#include <aidlcommonsupport/NativeHandle.h>
#include <android-base/macros.h>
#include <log/log.h>

#include <sys/mman.h>
#include <cinttypes>

#include <cutils/ashmem.h>

using ::aidl::android::hardware::sensors::BnSensors;
using ::aidl::android::hardware::sensors::Event;
using ::aidl::android::hardware::sensors::ISensors;
using ::aidl::android::hardware::sensors::SensorType;

template <class SensorType, class Event>
class SensorsAidlTestSharedMemory {
  public:
    static SensorsAidlTestSharedMemory* create(ISensors::SharedMemInfo::SharedMemType type,
                                               size_t size) {
        constexpr size_t kMaxSize =
                128 * 1024 * 1024;  // sensor test should not need more than 128M
        if (size == 0 || size >= kMaxSize) {
            return nullptr;
        }

        auto m = new SensorsAidlTestSharedMemory<SensorType, Event>(type, size);
        if (m->mSize != size || m->mBuffer == nullptr) {
            delete m;
            m = nullptr;
        }
        return m;
    }

    ISensors::SharedMemInfo getSharedMemInfo() const {
        ISensors::SharedMemInfo mem = {
                .type = mType,
                .format = ISensors::SharedMemInfo::SharedMemFormat::SENSORS_EVENT,
                .size = static_cast<int32_t>(mSize),
                .memoryHandle = android::dupToAidl(mNativeHandle)};
        return mem;
    }
    char* getBuffer() const { return mBuffer; }
    size_t getSize() const { return mSize; }
    std::vector<Event> parseEvents(int64_t lastCounter = -1, size_t offset = 0) const {
        constexpr size_t kEventSize =
                static_cast<size_t>(BnSensors::DIRECT_REPORT_SENSOR_EVENT_TOTAL_LENGTH);
        constexpr size_t kOffsetSize =
                static_cast<size_t>(BnSensors::DIRECT_REPORT_SENSOR_EVENT_OFFSET_SIZE_FIELD);
        constexpr size_t kOffsetToken =
                static_cast<size_t>(BnSensors::DIRECT_REPORT_SENSOR_EVENT_OFFSET_SIZE_REPORT_TOKEN);
        constexpr size_t kOffsetType =
                static_cast<size_t>(BnSensors::DIRECT_REPORT_SENSOR_EVENT_OFFSET_SIZE_SENSOR_TYPE);
        constexpr size_t kOffsetAtomicCounter = static_cast<size_t>(
                BnSensors::DIRECT_REPORT_SENSOR_EVENT_OFFSET_SIZE_ATOMIC_COUNTER);
        constexpr size_t kOffsetTimestamp =
                static_cast<size_t>(BnSensors::DIRECT_REPORT_SENSOR_EVENT_OFFSET_SIZE_TIMESTAMP);
        constexpr size_t kOffsetData =
                static_cast<size_t>(BnSensors::DIRECT_REPORT_SENSOR_EVENT_OFFSET_SIZE_DATA);

        std::vector<Event> events;
        std::vector<float> data(16);

        while (offset + kEventSize <= mSize) {
            int64_t atomicCounter =
                    *reinterpret_cast<uint32_t*>(mBuffer + offset + kOffsetAtomicCounter);
            if (atomicCounter <= lastCounter) {
                ALOGV("atomicCounter = %" PRId64 ", lastCounter = %" PRId64, atomicCounter,
                      lastCounter);
                break;
            }

            int32_t size = *reinterpret_cast<int32_t*>(mBuffer + offset + kOffsetSize);
            if (size != kEventSize) {
                // unknown error, events parsed may be wrong, remove all
                events.clear();
                break;
            }

            int32_t token = *reinterpret_cast<int32_t*>(mBuffer + offset + kOffsetToken);
            int32_t type = *reinterpret_cast<int32_t*>(mBuffer + offset + kOffsetType);
            int64_t timestamp = *reinterpret_cast<int64_t*>(mBuffer + offset + kOffsetTimestamp);

            ALOGV("offset = %zu, cnt %" PRId64 ", token %" PRId32 ", type %" PRId32
                  ", timestamp %" PRId64,
                  offset, atomicCounter, token, type, timestamp);

            Event event = {
                    .timestamp = timestamp,
                    .sensorHandle = token,
                    .sensorType = type,
            };

            event.set<Event::Data>(reinterpret_cast<float*>(mBuffer + offset + kOffsetData));
            // event.u.data = android::hardware::hidl_array<float,
            // 16>(reinterpret_cast<float*>(mBuffer + offset + kOffsetData));

            events.push_back(event);

            lastCounter = atomicCounter;
            offset += kEventSize;
        }

        return events;
    }

    virtual ~SensorsAidlTestSharedMemory() {
        switch (mType) {
            case ISensors::SharedMemInfo::SharedMemType::ASHMEM: {
                if (mSize != 0) {
                    ::munmap(mBuffer, mSize);
                    mBuffer = nullptr;

                    ::native_handle_close(mNativeHandle);
                    ::native_handle_delete(mNativeHandle);

                    mNativeHandle = nullptr;
                    mSize = 0;
                }
                break;
            }
            case ISensors::SharedMemInfo::SharedMemType::GRALLOC: {
                if (mSize != 0) {
                    mGrallocWrapper->freeBuffer(mNativeHandle);
                    mNativeHandle = nullptr;
                    mSize = 0;
                }
                break;
            }
            default: {
                if (mNativeHandle != nullptr || mSize != 0 || mBuffer != nullptr) {
                    ALOGE("SensorsAidlTestSharedMemory %p not properly destructed: "
                          "type %d, native handle %p, size %zu, buffer %p",
                          this, static_cast<int>(mType), mNativeHandle, mSize, mBuffer);
                }
                break;
            }
        }
    }

  private:
    SensorsAidlTestSharedMemory(ISensors::SharedMemInfo::SharedMemType type, size_t size)
        : mType(type), mSize(0), mBuffer(nullptr) {
        native_handle_t* handle = nullptr;
        char* buffer = nullptr;
        switch (type) {
            case ISensors::SharedMemInfo::SharedMemType::ASHMEM: {
                int fd;
                handle = ::native_handle_create(1 /*nFds*/, 0 /*nInts*/);
                if (handle != nullptr) {
                    handle->data[0] = fd =
                            ::ashmem_create_region("SensorsAidlTestSharedMemory", size);
                    if (handle->data[0] > 0) {
                        // memory is pinned by default
                        buffer = static_cast<char*>(
                                ::mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0));
                        if (buffer != reinterpret_cast<char*>(MAP_FAILED)) {
                            break;
                        }
                        ::native_handle_close(handle);
                    }
                    ::native_handle_delete(handle);
                    handle = nullptr;
                }
                break;
            }
            case ISensors::SharedMemInfo::SharedMemType::GRALLOC: {
                mGrallocWrapper = std::make_unique<::android::GrallocWrapper>();
                if (!mGrallocWrapper->isInitialized()) {
                    break;
                }

                std::pair<native_handle_t*, void*> buf = mGrallocWrapper->allocate(size);
                handle = buf.first;
                buffer = static_cast<char*>(buf.second);
                break;
            }
            default:
                break;
        }

        if (buffer != nullptr) {
            mNativeHandle = handle;
            mSize = size;
            mBuffer = buffer;
        }
    }

    ISensors::SharedMemInfo::SharedMemType mType;
    native_handle_t* mNativeHandle;
    size_t mSize;
    char* mBuffer;
    std::unique_ptr<::android::GrallocWrapper> mGrallocWrapper;

    DISALLOW_COPY_AND_ASSIGN(SensorsAidlTestSharedMemory);
};

#endif  // ANDROID_SENSORS_TEST_SHARED_MEMORY_H
+196 −2
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@
#include <utils/SystemClock.h>

#include "SensorsAidlEnvironment.h"
#include "SensorsAidlTestSharedMemory.h"
#include "sensors-vts-utils/SensorsVtsEnvironmentBase.h"

#include <cinttypes>
@@ -43,6 +44,9 @@ using aidl::android::hardware::sensors::SensorType;
using android::ProcessState;
using std::chrono::duration_cast;

constexpr size_t kEventSize =
        static_cast<size_t>(ISensors::DIRECT_REPORT_SENSOR_EVENT_TOTAL_LENGTH);

namespace {

static void assertTypeMatchStringType(SensorType type, const std::string& stringType) {
@@ -97,6 +101,24 @@ static void assertTypeMatchStringType(SensorType type, const std::string& string
    }
}

bool isDirectChannelTypeSupported(SensorInfo sensor, ISensors::SharedMemInfo::SharedMemType type) {
    switch (type) {
        case ISensors::SharedMemInfo::SharedMemType::ASHMEM:
            return (sensor.flags & SensorInfo::SENSOR_FLAG_BITS_DIRECT_CHANNEL_ASHMEM) != 0;
        case ISensors::SharedMemInfo::SharedMemType::GRALLOC:
            return (sensor.flags & SensorInfo::SENSOR_FLAG_BITS_DIRECT_CHANNEL_GRALLOC) != 0;
        default:
            return false;
    }
}

bool isDirectReportRateSupported(SensorInfo sensor, ISensors::RateLevel rate) {
    unsigned int r = static_cast<unsigned int>(sensor.flags &
                                               SensorInfo::SENSOR_FLAG_BITS_MASK_DIRECT_REPORT) >>
                     static_cast<unsigned int>(SensorInfo::SENSOR_FLAG_SHIFT_DIRECT_REPORT);
    return r >= static_cast<unsigned int>(rate);
}

int expectedReportModeForType(SensorType type) {
    switch (type) {
        case SensorType::ACCELEROMETER:
@@ -286,6 +308,24 @@ class SensorsAidlTest : public testing::TestWithParam<std::string> {
    std::vector<SensorInfo> getOneShotSensors();
    std::vector<SensorInfo> getInjectEventSensors();

    void verifyDirectChannel(ISensors::SharedMemInfo::SharedMemType memType);

    void verifyRegisterDirectChannel(
            std::shared_ptr<SensorsAidlTestSharedMemory<SensorType, Event>> mem,
            int32_t* directChannelHandle, bool supportsSharedMemType,
            bool supportsAnyDirectChannel);

    void verifyConfigure(const SensorInfo& sensor, ISensors::SharedMemInfo::SharedMemType memType,
                         int32_t directChannelHandle, bool directChannelSupported);

    void queryDirectChannelSupport(ISensors::SharedMemInfo::SharedMemType memType,
                                   bool* supportsSharedMemType, bool* supportsAnyDirectChannel);

    void verifyUnregisterDirectChannel(int32_t* directChannelHandle, bool supportsAnyDirectChannel);

    void checkRateLevel(const SensorInfo& sensor, int32_t directChannelHandle,
                        ISensors::RateLevel rateLevel, int32_t* reportToken);

    inline std::shared_ptr<ISensors>& getSensors() { return mEnvironment->mSensors; }

    inline SensorsAidlEnvironment* getEnvironment() { return mEnvironment; }
@@ -313,6 +353,18 @@ class SensorsAidlTest : public testing::TestWithParam<std::string> {

    ndk::ScopedAStatus flush(int32_t sensorHandle) { return getSensors()->flush(sensorHandle); }

    ndk::ScopedAStatus registerDirectChannel(const ISensors::SharedMemInfo& mem,
                                             int32_t* aidlReturn);

    ndk::ScopedAStatus unregisterDirectChannel(int32_t* channelHandle) {
        return getSensors()->unregisterDirectChannel(*channelHandle);
    }

    ndk::ScopedAStatus configDirectReport(int32_t sensorHandle, int32_t channelHandle,
                                          ISensors::RateLevel rate, int32_t* reportToken) {
        return getSensors()->configDirectReport(sensorHandle, channelHandle, rate, reportToken);
    }

    void runSingleFlushTest(const std::vector<SensorInfo>& sensors, bool activateSensor,
                            int32_t expectedFlushCount, bool expectedResult);

@@ -334,6 +386,19 @@ class SensorsAidlTest : public testing::TestWithParam<std::string> {
    SensorsAidlEnvironment* mEnvironment;
};

ndk::ScopedAStatus SensorsAidlTest::registerDirectChannel(const ISensors::SharedMemInfo& mem,
                                                          int32_t* aidlReturn) {
    // If registeration of a channel succeeds, add the handle of channel to a set so that it can be
    // unregistered when test fails. Unregister a channel does not remove the handle on purpose.
    // Unregistering a channel more than once should not have negative effect.

    ndk::ScopedAStatus status = getSensors()->registerDirectChannel(mem, aidlReturn);
    if (status.isOk()) {
        mDirectChannelHandles.insert(*aidlReturn);
    }
    return status;
}

std::vector<SensorInfo> SensorsAidlTest::getSensorsList() {
    std::vector<SensorInfo> sensorInfoList;
    checkIsOk(getSensors()->getSensorsList(&sensorInfoList));
@@ -850,12 +915,141 @@ TEST_P(SensorsAidlTest, NoStaleEvents) {
    }
}

void SensorsAidlTest::checkRateLevel(const SensorInfo& sensor, int32_t directChannelHandle,
                                     ISensors::RateLevel rateLevel, int32_t* reportToken) {
    ndk::ScopedAStatus status =
            configDirectReport(sensor.sensorHandle, directChannelHandle, rateLevel, reportToken);

    SCOPED_TRACE(::testing::Message()
                 << " handle=0x" << std::hex << std::setw(8) << std::setfill('0')
                 << sensor.sensorHandle << std::dec << " type=" << static_cast<int>(sensor.type)
                 << " name=" << sensor.name);

    if (isDirectReportRateSupported(sensor, rateLevel)) {
        ASSERT_TRUE(status.isOk());
        if (rateLevel != ISensors::RateLevel::STOP) {
            ASSERT_GT(*reportToken, 0);
        } else {
            ASSERT_EQ(status.getExceptionCode(), EX_ILLEGAL_ARGUMENT);
        }
    }
}

void SensorsAidlTest::queryDirectChannelSupport(ISensors::SharedMemInfo::SharedMemType memType,
                                                bool* supportsSharedMemType,
                                                bool* supportsAnyDirectChannel) {
    *supportsSharedMemType = false;
    *supportsAnyDirectChannel = false;
    for (const SensorInfo& curSensor : getSensorsList()) {
        if (isDirectChannelTypeSupported(curSensor, memType)) {
            *supportsSharedMemType = true;
        }
        if (isDirectChannelTypeSupported(curSensor,
                                         ISensors::SharedMemInfo::SharedMemType::ASHMEM) ||
            isDirectChannelTypeSupported(curSensor,
                                         ISensors::SharedMemInfo::SharedMemType::GRALLOC)) {
            *supportsAnyDirectChannel = true;
        }

        if (*supportsSharedMemType && *supportsAnyDirectChannel) {
            break;
        }
    }
}

void SensorsAidlTest::verifyRegisterDirectChannel(
        std::shared_ptr<SensorsAidlTestSharedMemory<SensorType, Event>> mem,
        int32_t* directChannelHandle, bool supportsSharedMemType, bool supportsAnyDirectChannel) {
    char* buffer = mem->getBuffer();
    size_t size = mem->getSize();

    if (supportsSharedMemType) {
        memset(buffer, 0xff, size);
    }

    int32_t channelHandle;

    ::ndk::ScopedAStatus status = registerDirectChannel(mem->getSharedMemInfo(), &channelHandle);
    if (supportsSharedMemType) {
        ASSERT_TRUE(status.isOk());
        ASSERT_EQ(channelHandle, 0);
    } else {
        int32_t error = supportsAnyDirectChannel ? EX_ILLEGAL_ARGUMENT : EX_UNSUPPORTED_OPERATION;
        ASSERT_EQ(status.getExceptionCode(), error);
        ASSERT_EQ(channelHandle, -1);
    }
    directChannelHandle = &channelHandle;
}

void SensorsAidlTest::verifyUnregisterDirectChannel(int32_t* channelHandle,
                                                    bool supportsAnyDirectChannel) {
    int result = supportsAnyDirectChannel ? EX_NONE : EX_UNSUPPORTED_OPERATION;
    ndk::ScopedAStatus status = unregisterDirectChannel(channelHandle);
    ASSERT_EQ(status.getExceptionCode(), result);
}

void SensorsAidlTest::verifyDirectChannel(ISensors::SharedMemInfo::SharedMemType memType) {
    constexpr size_t kNumEvents = 1;
    constexpr size_t kMemSize = kNumEvents * kEventSize;

    std::shared_ptr<SensorsAidlTestSharedMemory<SensorType, Event>> mem(
            SensorsAidlTestSharedMemory<SensorType, Event>::create(memType, kMemSize));
    ASSERT_NE(mem, nullptr);

    bool supportsSharedMemType;
    bool supportsAnyDirectChannel;
    queryDirectChannelSupport(memType, &supportsSharedMemType, &supportsAnyDirectChannel);

    for (const SensorInfo& sensor : getSensorsList()) {
        int32_t directChannelHandle = 0;
        verifyRegisterDirectChannel(mem, &directChannelHandle, supportsSharedMemType,
                                    supportsAnyDirectChannel);
        verifyConfigure(sensor, memType, directChannelHandle, supportsAnyDirectChannel);
        verifyUnregisterDirectChannel(&directChannelHandle, supportsAnyDirectChannel);
    }
}

void SensorsAidlTest::verifyConfigure(const SensorInfo& sensor,
                                      ISensors::SharedMemInfo::SharedMemType memType,
                                      int32_t directChannelHandle, bool supportsAnyDirectChannel) {
    SCOPED_TRACE(::testing::Message()
                 << " handle=0x" << std::hex << std::setw(8) << std::setfill('0')
                 << sensor.sensorHandle << std::dec << " type=" << static_cast<int>(sensor.type)
                 << " name=" << sensor.name);

    int32_t reportToken = 0;
    if (isDirectChannelTypeSupported(sensor, memType)) {
        // Verify that each rate level is properly supported
        checkRateLevel(sensor, directChannelHandle, ISensors::RateLevel::NORMAL, &reportToken);
        checkRateLevel(sensor, directChannelHandle, ISensors::RateLevel::FAST, &reportToken);
        checkRateLevel(sensor, directChannelHandle, ISensors::RateLevel::VERY_FAST, &reportToken);
        checkRateLevel(sensor, directChannelHandle, ISensors::RateLevel::STOP, &reportToken);

        // Verify that a sensor handle of -1 is only acceptable when using RateLevel::STOP
        ndk::ScopedAStatus status = configDirectReport(-1 /* sensorHandle */, directChannelHandle,
                                                       ISensors::RateLevel::NORMAL, &reportToken);
        ASSERT_EQ(status.getServiceSpecificError(), android::BAD_VALUE);

        status = configDirectReport(-1 /* sensorHandle */, directChannelHandle,
                                    ISensors::RateLevel::STOP, &reportToken);
        ASSERT_TRUE(status.isOk());
    } else {
        // directChannelHandle will be -1 here, HAL should either reject it as a bad value if there
        // is some level of direct channel report, otherwise return INVALID_OPERATION if direct
        // channel is not supported at all
        int error = supportsAnyDirectChannel ? EX_ILLEGAL_ARGUMENT : EX_UNSUPPORTED_OPERATION;
        ndk::ScopedAStatus status = configDirectReport(sensor.sensorHandle, directChannelHandle,
                                                       ISensors::RateLevel::NORMAL, &reportToken);
        ASSERT_EQ(status.getExceptionCode(), error);
    }
}

TEST_P(SensorsAidlTest, DirectChannelAshmem) {
    // TODO(b/195593357): Implement this
    verifyDirectChannel(ISensors::SharedMemInfo::SharedMemType::ASHMEM);
}

TEST_P(SensorsAidlTest, DirectChannelGralloc) {
    // TODO(b/195593357): Implement this
    verifyDirectChannel(ISensors::SharedMemInfo::SharedMemType::GRALLOC);
}

GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(SensorsAidlTest);