Merge "TV Input HAL 2.0 VTS"

This commit is contained in:
Yixiao Luo 2022-08-26 23:19:47 +00:00 committed by Android (Google) Code Review
commit f8de1e8e49
3 changed files with 415 additions and 0 deletions

View file

@ -0,0 +1,29 @@
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,
}

View file

@ -0,0 +1,296 @@
/*
* 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);

View file

@ -0,0 +1,90 @@
/*
* 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