1
0
Fork 0
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

346 lines
12 KiB

This file contains invisible Unicode characters!

This file contains invisible Unicode characters that may be processed differently from what appears below. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to reveal hidden characters.

/*
* Copyright (C) 2017 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 "tv_input_hidl_hal_test"
#include <android-base/logging.h>
#include <android/hardware/tv/input/1.0/ITvInput.h>
#include <android/hardware/tv/input/1.0/ITvInputCallback.h>
#include <android/hardware/tv/input/1.0/types.h>
#include <gtest/gtest.h>
#include <hidl/GtestPrinter.h>
#include <hidl/ServiceManagement.h>
#include <utils/KeyedVector.h>
#include <mutex>
#include <vector>
using ::android::hardware::tv::input::V1_0::ITvInput;
using ::android::hardware::tv::input::V1_0::ITvInputCallback;
using ::android::hardware::tv::input::V1_0::Result;
using ::android::hardware::tv::input::V1_0::TvInputType;
using ::android::hardware::tv::input::V1_0::TvInputDeviceInfo;
using ::android::hardware::tv::input::V1_0::TvInputEventType;
using ::android::hardware::tv::input::V1_0::TvInputEvent;
using ::android::hardware::tv::input::V1_0::TvStreamConfig;
using ::android::hardware::Return;
using ::android::hardware::Void;
using ::android::hardware::hidl_vec;
using ::android::sp;
#define WAIT_FOR_EVENT_TIMEOUT 5
#define DEFAULT_ID INT32_MIN
/* The main test class for TV Input HIDL HAL. */
class TvInputHidlTest : public testing::TestWithParam<std::string> {
public:
virtual void SetUp() override {
tv_input_ = ITvInput::getService(GetParam());
tv_input_callback_ = new TvInputCallback(*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);
}
virtual void TearDown() override {}
/* Called when a DEVICE_AVAILABLE event is received. */
void onDeviceAvailable(const TvInputDeviceInfo& deviceInfo) {
device_info_.add(deviceInfo.deviceId, deviceInfo);
}
/* Called when a DEVICE_UNAVAILABLE event is received. */
void onDeviceUnavailable(int32_t deviceId) { device_info_.removeItem(deviceId); }
/* Called when a DEVICE_CONFIGURATIONS_CHANGED event is received. */
Result onStreamConfigurationsChanged(int32_t deviceId) {
return updateStreamConfigurations(deviceId);
}
/* Gets and updates the stream configurations for a device. */
Result updateStreamConfigurations(int32_t deviceId) {
stream_config_.removeItem(deviceId);
Result result = Result::UNKNOWN;
hidl_vec<TvStreamConfig> list;
tv_input_->getStreamConfigurations(
deviceId, [&result, &list](Result res, hidl_vec<TvStreamConfig> configs) {
result = res;
if (res == Result::OK) {
list = configs;
}
});
if (result == Result::OK) {
stream_config_.add(deviceId, list);
}
return result;
}
/* Gets and updates the stream configurations for all existing devices. */
void updateAllStreamConfigurations() {
for (size_t i = 0; i < device_info_.size(); i++) {
int32_t device_id = device_info_.keyAt(i);
updateStreamConfigurations(device_id);
}
}
/* Returns a list of indices of stream_config_ whose corresponding values are not empty. */
std::vector<size_t> getConfigIndices() {
std::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;
}
/*
* 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(std::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]) {
std::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;
}
/* A simple test implementation of TvInputCallback for TV Input Events. */
class TvInputCallback : public ITvInputCallback {
public:
TvInputCallback(TvInputHidlTest& parent) : parent_(parent){};
virtual ~TvInputCallback() = default;
/*
* Notifies the client that an event has occurred. For possible event types,
* check TvInputEventType.
     */
Return<void> notify(const TvInputEvent& event) override {
std::unique_lock<std::mutex> lock(parent_.mutex_);
switch (event.type) {
case TvInputEventType::DEVICE_AVAILABLE:
parent_.onDeviceAvailable(event.deviceInfo);
break;
case TvInputEventType::DEVICE_UNAVAILABLE:
parent_.onDeviceUnavailable(event.deviceInfo.deviceId);
break;
case TvInputEventType::STREAM_CONFIGURATIONS_CHANGED:
parent_.onStreamConfigurationsChanged(event.deviceInfo.deviceId);
break;
}
return Void();
};
private:
/* The test contains this callback instance. */
TvInputHidlTest& parent_;
};
/* The TvInput used for the test. */
sp<ITvInput> tv_input_;
/* The TvInputCallback used for the test. */
sp<ITvInputCallback> tv_input_callback_;
/*
* A KeyedVector stores device information of every available device.
* A key is a device ID and the corresponding value is the TvInputDeviceInfo.
*/
android::KeyedVector<int32_t, TvInputDeviceInfo> device_info_;
/*
* A KeyedVector stores a list of stream configurations of every available device.
* A key is a device ID and the corresponding value is the stream configuration list.
*/
android::KeyedVector<int32_t, hidl_vec<TvStreamConfig>> stream_config_;
/* The mutex controls the access of shared data. */
std::mutex mutex_;
};
/*
* GetStreamConfigTest:
* Calls updateStreamConfigurations() for each existing device
* Checks returned results
*/
TEST_P(TvInputHidlTest, GetStreamConfigTest) {
std::unique_lock<std::mutex> lock(mutex_);
for (size_t i = 0; i < device_info_.size(); i++) {
int32_t device_id = device_info_.keyAt(i);
Result result = updateStreamConfigurations(device_id);
EXPECT_EQ(Result::OK, result);
}
}
/*
* OpenAndCloseStreamTest:
* Calls openStream() and then closeStream() for each existing stream
* Checks returned results
*/
TEST_P(TvInputHidlTest, OpenAndCloseStreamTest) {
std::unique_lock<std::mutex> lock(mutex_);
updateAllStreamConfigurations();
for (size_t j = 0; j < stream_config_.size(); j++) {
int32_t device_id = stream_config_.keyAt(j);
hidl_vec<TvStreamConfig> config = stream_config_.valueAt(j);
for (size_t i = 0; i < config.size(); i++) {
Result result = Result::UNKNOWN;
int32_t stream_id = config[i].streamId;
tv_input_->openStream(device_id, stream_id,
[&result](Result res, const native_handle_t*) { result = res; });
EXPECT_EQ(Result::OK, result);
result = Result::UNKNOWN;
result = tv_input_->closeStream(device_id, stream_id);
EXPECT_EQ(Result::OK, result);
}
}
}
/*
* InvalidDeviceIdTest:
* Calls updateStreamConfigurations(), openStream(), and closeStream()
* for a non-existing device
* Checks returned results
* The results should be Result::INVALID_ARGUMENTS
*/
TEST_P(TvInputHidlTest, InvalidDeviceIdTest) {
std::unique_lock<std::mutex> lock(mutex_);
std::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);
EXPECT_EQ(Result::INVALID_ARGUMENTS, updateStreamConfigurations(id));
Result result = Result::UNKNOWN;
int32_t stream_id = 0;
tv_input_->openStream(id, stream_id,
[&result](Result res, const native_handle_t*) { result = res; });
EXPECT_EQ(Result::INVALID_ARGUMENTS, result);
result = Result::UNKNOWN;
result = tv_input_->closeStream(id, stream_id);
EXPECT_EQ(Result::INVALID_ARGUMENTS, result);
}
/*
* InvalidStreamIdTest:
* Calls openStream(), and closeStream() for a non-existing stream
* Checks returned results
* The results should be Result::INVALID_ARGUMENTS
*/
TEST_P(TvInputHidlTest, InvalidStreamIdTest) {
std::unique_lock<std::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) {
std::vector<int32_t> stream_ids;
hidl_vec<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);
}
Result result = Result::UNKNOWN;
tv_input_->openStream(device_id, id,
[&result](Result res, const native_handle_t*) { result = res; });
EXPECT_EQ(Result::INVALID_ARGUMENTS, result);
result = Result::UNKNOWN;
result = tv_input_->closeStream(device_id, id);
EXPECT_EQ(Result::INVALID_ARGUMENTS, result);
}
/*
* OpenAnOpenedStreamsTest:
* Calls openStream() twice for a stream (if any)
* Checks returned results
* The result of the second call should be Result::INVALID_STATE
*/
TEST_P(TvInputHidlTest, OpenAnOpenedStreamsTest) {
std::unique_lock<std::mutex> lock(mutex_);
updateAllStreamConfigurations();
std::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;
Result result = Result::UNKNOWN;
tv_input_->openStream(device_id, stream_id,
[&result](Result res, const native_handle_t*) { result = res; });
EXPECT_EQ(Result::OK, result);
tv_input_->openStream(device_id, stream_id,
[&result](Result res, const native_handle_t*) { result = res; });
EXPECT_EQ(Result::INVALID_STATE, result);
// close stream as subsequent tests assume no open streams
EXPECT_EQ(Result::OK, tv_input_->closeStream(device_id, stream_id));
}
/*
* CloseStreamBeforeOpenTest:
* Calls closeStream() without calling openStream() for a stream (if any)
* Checks the returned result
* The result should be Result::INVALID_STATE
*/
TEST_P(TvInputHidlTest, CloseStreamBeforeOpenTest) {
std::unique_lock<std::mutex> lock(mutex_);
updateAllStreamConfigurations();
std::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;
EXPECT_EQ(Result::INVALID_STATE, tv_input_->closeStream(device_id, stream_id));
}
INSTANTIATE_TEST_SUITE_P(
PerInstance, TvInputHidlTest,
testing::ValuesIn(android::hardware::getAllHalInstanceNames(ITvInput::descriptor)),
android::hardware::PrintInstanceNameToString);
// TODO remove from the allow list once the cf tv target is enabled for testing
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(TvInputHidlTest);