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

Commit f8de1e8e authored by Yixiao Luo's avatar Yixiao Luo Committed by Android (Google) Code Review
Browse files

Merge "TV Input HAL 2.0 VTS"

parents dc5ed0b5 ce501336
Loading
Loading
Loading
Loading
+29 −0
Original line number Diff line number Diff line
package {
    // See: http://go/android-license-faq
    // A large-scale-change added 'default_applicable_licenses' to import
    // all of the 'license_kinds' from "hardware_interfaces_license"
    // to get the below license kinds:
    //   SPDX-license-identifier-Apache-2.0
    default_applicable_licenses: ["hardware_interfaces_license"],
}

cc_test {
    name: "VtsHalTvInputTargetTest",
    defaults: ["VtsHalTargetTestDefaults","use_libaidlvintf_gtest_helper_static",],
    srcs: ["VtsHalTvInputTargetTest.cpp"],
    static_libs: [
        "android.hardware.tv.input-V1-ndk",
        "android.media.audio.common.types-V1-ndk",
        "android.hardware.common-V2-ndk",
        "libaidlcommonsupport",
    ],
    test_suites: [
        "general-tests",
        "vts",
    ],
    shared_libs: [
        "libbinder_ndk",
        "libvndksupport",
    ],
    require_root: true,
}
+296 −0
Original line number Diff line number Diff line
/*
 * Copyright 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.
 */

#include "VtsHalTvInputTargetTest.h"

#include <android-base/properties.h>
#include <android/binder_ibinder.h>
#include <android/binder_process.h>
#include <android/binder_status.h>

using namespace VtsHalTvInputTargetTest;

TvInputAidlTest::TvInputCallback::TvInputCallback(shared_ptr<TvInputAidlTest> parent)
    : parent_(parent) {}

::ndk::ScopedAStatus TvInputAidlTest::TvInputCallback::notify(const TvInputEvent& in_event) {
    unique_lock<mutex> lock(parent_->mutex_);

    switch (in_event.type) {
        case TvInputEventType::DEVICE_AVAILABLE:
            parent_->onDeviceAvailable(in_event.deviceInfo);
            break;
        case TvInputEventType::DEVICE_UNAVAILABLE:
            parent_->onDeviceUnavailable(in_event.deviceInfo.deviceId);
            break;
        case TvInputEventType::STREAM_CONFIGURATIONS_CHANGED:
            parent_->onStreamConfigurationsChanged(in_event.deviceInfo.deviceId);
            break;
    }
    return ::ndk::ScopedAStatus::ok();
}

void TvInputAidlTest::SetUp() {
    if (AServiceManager_isDeclared(GetParam().c_str())) {
        ::ndk::SpAIBinder binder(AServiceManager_waitForService(GetParam().c_str()));
        tv_input_ = ITvInput::fromBinder(binder);
    } else {
        tv_input_ = nullptr;
    }
    ASSERT_NE(tv_input_, nullptr);

    tv_input_callback_ =
            ::ndk::SharedRefBase::make<TvInputCallback>(shared_ptr<TvInputAidlTest>(this));
    ASSERT_NE(tv_input_callback_, nullptr);

    tv_input_->setCallback(tv_input_callback_);
    // All events received within the timeout should be handled.
    sleep(WAIT_FOR_EVENT_TIMEOUT);
}

void TvInputAidlTest::TearDown() {
    tv_input_ = nullptr;
}

void TvInputAidlTest::onDeviceAvailable(const TvInputDeviceInfo& deviceInfo) {
    ALOGD("onDeviceAvailable for device id %d", deviceInfo.deviceId);
    device_info_.add(deviceInfo.deviceId, deviceInfo);
}

void TvInputAidlTest::onDeviceUnavailable(int32_t deviceId) {
    ALOGD("onDeviceUnavailable for device id %d", deviceId);
    device_info_.removeItem(deviceId);
    stream_config_.removeItem(deviceId);
}

::ndk::ScopedAStatus TvInputAidlTest::onStreamConfigurationsChanged(int32_t deviceId) {
    ALOGD("onStreamConfigurationsChanged for device id %d", deviceId);
    return updateStreamConfigurations(deviceId);
}

::ndk::ScopedAStatus TvInputAidlTest::updateStreamConfigurations(int32_t deviceId) {
    stream_config_.removeItem(deviceId);
    vector<TvStreamConfig> list;
    ::ndk::ScopedAStatus status = tv_input_->getStreamConfigurations(deviceId, &list);
    if (status.isOk()) {
        stream_config_.add(deviceId, list);
    }
    return status;
}

void TvInputAidlTest::updateAllStreamConfigurations() {
    for (size_t i = 0; i < device_info_.size(); i++) {
        int32_t device_id = device_info_.keyAt(i);
        updateStreamConfigurations(device_id);
    }
}

vector<size_t> TvInputAidlTest::getConfigIndices() {
    vector<size_t> indices;
    for (size_t i = 0; i < stream_config_.size(); i++) {
        if (stream_config_.valueAt(i).size() != 0) {
            indices.push_back(i);
        }
    }
    return indices;
}

int32_t TvInputAidlTest::getNumNotIn(vector<int32_t>& nums) {
    int32_t result = DEFAULT_ID;
    int32_t size = static_cast<int32_t>(nums.size());
    for (int32_t i = 0; i < size; i++) {
        // Put every element to its target position, if possible.
        int32_t target_pos = nums[i];
        while (target_pos >= 0 && target_pos < size && i != target_pos &&
               nums[i] != nums[target_pos]) {
            swap(nums[i], nums[target_pos]);
            target_pos = nums[i];
        }
    }

    for (int32_t i = 0; i < size; i++) {
        if (nums[i] != i) {
            return i;
        }
    }
    return result;
}

/*
 * GetStreamConfigTest:
 * Calls updateStreamConfigurations() for each existing device
 * Checks returned results
 */
TEST_P(TvInputAidlTest, GetStreamConfigTest) {
    unique_lock<mutex> lock(mutex_);

    for (size_t i = 0; i < device_info_.size(); i++) {
        int32_t device_id = device_info_.keyAt(i);
        ALOGD("GetStreamConfigTest: device_id=%d", device_id);
        ASSERT_TRUE(updateStreamConfigurations(device_id).isOk());
    }
}

/*
 * OpenAndCloseStreamTest:
 * Calls openStream() and then closeStream() for each existing stream
 * Checks returned results
 */
TEST_P(TvInputAidlTest, OpenAndCloseStreamTest) {
    unique_lock<mutex> lock(mutex_);

    updateAllStreamConfigurations();

    for (size_t j = 0; j < stream_config_.size(); j++) {
        int32_t device_id = stream_config_.keyAt(j);
        vector<TvStreamConfig> config = stream_config_.valueAt(j);
        for (size_t i = 0; i < config.size(); i++) {
            int32_t stream_id = config[i].streamId;
            ALOGD("OpenAndCloseStreamTest: open stream, device_id=%d, stream_id=%d", device_id,
                  stream_id);
            ASSERT_TRUE(tv_input_->openStream(device_id, stream_id, &handle_).isOk());
            ALOGD("OpenAndCloseStreamTest: close stream, device_id=%d, stream_id=%d", device_id,
                  stream_id);
            ASSERT_TRUE(tv_input_->closeStream(device_id, stream_id).isOk());
        }
    }
}

/*
 * InvalidDeviceIdTest:
 * Calls updateStreamConfigurations(), openStream(), and closeStream()
 * for a non-existing device
 * Checks returned results
 * The results should be ITvInput::STATUS_INVALID_ARGUMENTS
 */
TEST_P(TvInputAidlTest, InvalidDeviceIdTest) {
    unique_lock<mutex> lock(mutex_);

    vector<int32_t> device_ids;
    for (size_t i = 0; i < device_info_.size(); i++) {
        device_ids.push_back(device_info_.keyAt(i));
    }
    // Get a non-existing device ID.
    int32_t id = getNumNotIn(device_ids);
    ALOGD("InvalidDeviceIdTest: update stream config, device_id=%d", id);
    ASSERT_TRUE(updateStreamConfigurations(id).getServiceSpecificError() ==
                ITvInput::STATUS_INVALID_ARGUMENTS);

    int32_t stream_id = 0;

    ALOGD("InvalidDeviceIdTest: open stream, device_id=%d, stream_id=%d", id, stream_id);
    ASSERT_TRUE(tv_input_->openStream(id, stream_id, &handle_).getServiceSpecificError() ==
                ITvInput::STATUS_INVALID_ARGUMENTS);

    ALOGD("InvalidDeviceIdTest: close stream, device_id=%d, stream_id=%d", id, stream_id);
    ASSERT_TRUE(tv_input_->closeStream(id, stream_id).getServiceSpecificError() ==
                ITvInput::STATUS_INVALID_ARGUMENTS);
}

/*
 * InvalidStreamIdTest:
 * Calls openStream(), and closeStream() for a non-existing stream
 * Checks returned results
 * The results should be ITvInput::STATUS_INVALID_ARGUMENTS
 */
TEST_P(TvInputAidlTest, InvalidStreamIdTest) {
    unique_lock<mutex> lock(mutex_);

    if (device_info_.isEmpty()) {
        return;
    }
    updateAllStreamConfigurations();

    int32_t device_id = device_info_.keyAt(0);
    // Get a non-existing stream ID.
    int32_t id = DEFAULT_ID;
    if (stream_config_.indexOfKey(device_id) >= 0) {
        vector<int32_t> stream_ids;
        vector<TvStreamConfig> config = stream_config_.valueFor(device_id);
        for (size_t i = 0; i < config.size(); i++) {
            stream_ids.push_back(config[i].streamId);
        }
        id = getNumNotIn(stream_ids);
    }

    ALOGD("InvalidStreamIdTest: open stream, device_id=%d, stream_id=%d", device_id, id);
    ASSERT_TRUE(tv_input_->openStream(device_id, id, &handle_).getServiceSpecificError() ==
                ITvInput::STATUS_INVALID_ARGUMENTS);

    ALOGD("InvalidStreamIdTest: close stream, device_id=%d, stream_id=%d", device_id, id);
    ASSERT_TRUE(tv_input_->closeStream(device_id, id).getServiceSpecificError() ==
                ITvInput::STATUS_INVALID_ARGUMENTS);
}

/*
 * OpenAnOpenedStreamsTest:
 * Calls openStream() twice for a stream (if any)
 * Checks returned results
 * The result of the second call should be ITvInput::STATUS_INVALID_STATE
 */
TEST_P(TvInputAidlTest, OpenAnOpenedStreamsTest) {
    unique_lock<mutex> lock(mutex_);

    updateAllStreamConfigurations();
    vector<size_t> indices = getConfigIndices();
    if (indices.empty()) {
        return;
    }
    int32_t device_id = stream_config_.keyAt(indices[0]);
    int32_t stream_id = stream_config_.valueAt(indices[0])[0].streamId;

    ALOGD("OpenAnOpenedStreamsTest: open stream, device_id=%d, stream_id=%d", device_id, stream_id);
    ASSERT_TRUE(tv_input_->openStream(device_id, stream_id, &handle_).isOk());

    ALOGD("OpenAnOpenedStreamsTest: open stream, device_id=%d, stream_id=%d", device_id, stream_id);
    ASSERT_TRUE(tv_input_->openStream(device_id, stream_id, &handle_).getServiceSpecificError() ==
                ITvInput::STATUS_INVALID_STATE);

    // close stream as subsequent tests assume no open streams
    ALOGD("OpenAnOpenedStreamsTest: close stream, device_id=%d, stream_id=%d", device_id,
          stream_id);
    ASSERT_TRUE(tv_input_->closeStream(device_id, stream_id).isOk());
}

/*
 * CloseStreamBeforeOpenTest:
 * Calls closeStream() without calling openStream() for a stream (if any)
 * Checks the returned result
 * The result should be ITvInput::STATUS_INVALID_STATE
 */
TEST_P(TvInputAidlTest, CloseStreamBeforeOpenTest) {
    unique_lock<mutex> lock(mutex_);

    updateAllStreamConfigurations();
    vector<size_t> indices = getConfigIndices();
    if (indices.empty()) {
        return;
    }
    int32_t device_id = stream_config_.keyAt(indices[0]);
    int32_t stream_id = stream_config_.valueAt(indices[0])[0].streamId;

    ALOGD("CloseStreamBeforeOpenTest: close stream, device_id=%d, stream_id=%d", device_id,
          stream_id);
    ASSERT_TRUE(tv_input_->closeStream(device_id, stream_id).getServiceSpecificError() ==
                ITvInput::STATUS_INVALID_STATE);
}

INSTANTIATE_TEST_SUITE_P(PerInstance, TvInputAidlTest,
                         testing::ValuesIn(android::getAidlHalInstanceNames(ITvInput::descriptor)),
                         android::PrintInstanceNameToString);

// TODO remove from the allow list once the cf tv target is enabled for testing
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(TvInputAidlTest);
+90 −0
Original line number Diff line number Diff line
/*
 * Copyright 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.
 */

#pragma once

#include <android/binder_manager.h>

#include <aidl/Gtest.h>
#include <aidl/Vintf.h>

#include <aidl/android/hardware/tv/input/BnTvInputCallback.h>
#include <aidl/android/hardware/tv/input/ITvInput.h>
#include <aidl/android/hardware/tv/input/TvInputDeviceInfo.h>
#include <aidl/android/hardware/tv/input/TvInputEvent.h>
#include <aidl/android/hardware/tv/input/TvStreamConfig.h>

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

using namespace aidl::android::hardware::tv::input;
using namespace std;

using ::aidl::android::hardware::common::NativeHandle;

#define WAIT_FOR_EVENT_TIMEOUT 5
#define DEFAULT_ID INT32_MIN

namespace VtsHalTvInputTargetTest {

class TvInputAidlTest : public testing::TestWithParam<string> {
  public:
    class TvInputCallback : public BnTvInputCallback {
      public:
        TvInputCallback(shared_ptr<TvInputAidlTest> parent);
        ::ndk::ScopedAStatus notify(const TvInputEvent& in_event) override;

      private:
        shared_ptr<TvInputAidlTest> parent_;
    };

    virtual void SetUp() override;
    virtual void TearDown() override;

    /* Called when a DEVICE_AVAILABLE event is received. */
    void onDeviceAvailable(const TvInputDeviceInfo& deviceInfo);

    /* Called when a DEVICE_UNAVAILABLE event is received. */
    void onDeviceUnavailable(int32_t deviceId);

    /* Called when a STREAM_CONFIGURATIONS_CHANGED event is received. */
    ::ndk::ScopedAStatus onStreamConfigurationsChanged(int32_t deviceId);

    /* Gets and updates the stream configurations for a device. */
    ::ndk::ScopedAStatus updateStreamConfigurations(int32_t deviceId);

    /* Gets and updates the stream configurations for all existing devices. */
    void updateAllStreamConfigurations();

    /* Returns a list of indices of stream_config_ whose corresponding values are not empty. */
    vector<size_t> getConfigIndices();

    /*
     * Returns DEFAULT_ID if there is no missing integer in the range [0, the size of nums).
     * Otherwise, returns the smallest missing non-negative integer.
     */
    int32_t getNumNotIn(vector<int32_t>& nums);

  protected:
    shared_ptr<ITvInput> tv_input_;
    shared_ptr<TvInputCallback> tv_input_callback_;
    android::KeyedVector<int32_t, TvInputDeviceInfo> device_info_;
    android::KeyedVector<int32_t, vector<TvStreamConfig>> stream_config_;
    mutex mutex_;
    NativeHandle handle_;
};

}  // namespace VtsHalTvInputTargetTest