1 /*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #define LOG_TAG "tv_input_hidl_hal_test"
18 #include <android-base/logging.h>
19
20 #include <android/hardware/tv/input/1.0/ITvInput.h>
21 #include <android/hardware/tv/input/1.0/ITvInputCallback.h>
22 #include <android/hardware/tv/input/1.0/types.h>
23 #include <gtest/gtest.h>
24 #include <hidl/GtestPrinter.h>
25 #include <hidl/ServiceManagement.h>
26 #include <utils/KeyedVector.h>
27 #include <mutex>
28 #include <vector>
29
30 using ::android::hardware::tv::input::V1_0::ITvInput;
31 using ::android::hardware::tv::input::V1_0::ITvInputCallback;
32 using ::android::hardware::tv::input::V1_0::Result;
33 using ::android::hardware::tv::input::V1_0::TvInputType;
34 using ::android::hardware::tv::input::V1_0::TvInputDeviceInfo;
35 using ::android::hardware::tv::input::V1_0::TvInputEventType;
36 using ::android::hardware::tv::input::V1_0::TvInputEvent;
37 using ::android::hardware::tv::input::V1_0::TvStreamConfig;
38 using ::android::hardware::Return;
39 using ::android::hardware::Void;
40 using ::android::hardware::hidl_vec;
41 using ::android::sp;
42
43 #define WAIT_FOR_EVENT_TIMEOUT 5
44 #define DEFAULT_ID INT32_MIN
45
46 /* The main test class for TV Input HIDL HAL. */
47 class TvInputHidlTest : public testing::TestWithParam<std::string> {
48 public:
SetUp()49 virtual void SetUp() override {
50 tv_input_ = ITvInput::getService(GetParam());
51 tv_input_callback_ = new TvInputCallback(*this);
52 ASSERT_NE(tv_input_callback_, nullptr);
53 tv_input_->setCallback(tv_input_callback_);
54 // All events received within the timeout should be handled.
55 sleep(WAIT_FOR_EVENT_TIMEOUT);
56 }
57
TearDown()58 virtual void TearDown() override {}
59
60 /* Called when a DEVICE_AVAILABLE event is received. */
onDeviceAvailable(const TvInputDeviceInfo & deviceInfo)61 void onDeviceAvailable(const TvInputDeviceInfo& deviceInfo) {
62 device_info_.add(deviceInfo.deviceId, deviceInfo);
63 }
64
65 /* Called when a DEVICE_UNAVAILABLE event is received. */
onDeviceUnavailable(int32_t deviceId)66 void onDeviceUnavailable(int32_t deviceId) { device_info_.removeItem(deviceId); }
67
68 /* Called when a DEVICE_CONFIGURATIONS_CHANGED event is received. */
onStreamConfigurationsChanged(int32_t deviceId)69 Result onStreamConfigurationsChanged(int32_t deviceId) {
70 return updateStreamConfigurations(deviceId);
71 }
72
73 /* Gets and updates the stream configurations for a device. */
updateStreamConfigurations(int32_t deviceId)74 Result updateStreamConfigurations(int32_t deviceId) {
75 stream_config_.removeItem(deviceId);
76 Result result = Result::UNKNOWN;
77 hidl_vec<TvStreamConfig> list;
78 tv_input_->getStreamConfigurations(
79 deviceId, [&result, &list](Result res, hidl_vec<TvStreamConfig> configs) {
80 result = res;
81 if (res == Result::OK) {
82 list = configs;
83 }
84 });
85 if (result == Result::OK) {
86 stream_config_.add(deviceId, list);
87 }
88 return result;
89 }
90
91 /* Gets and updates the stream configurations for all existing devices. */
updateAllStreamConfigurations()92 void updateAllStreamConfigurations() {
93 for (size_t i = 0; i < device_info_.size(); i++) {
94 int32_t device_id = device_info_.keyAt(i);
95 updateStreamConfigurations(device_id);
96 }
97 }
98
99 /* Returns a list of indices of stream_config_ whose corresponding values are not empty. */
getConfigIndices()100 std::vector<size_t> getConfigIndices() {
101 std::vector<size_t> indices;
102 for (size_t i = 0; i < stream_config_.size(); i++) {
103 if (stream_config_.valueAt(i).size() != 0) {
104 indices.push_back(i);
105 }
106 }
107 return indices;
108 }
109
110 /*
111 * Returns DEFAULT_ID if there is no missing integer in the range [0, the size of nums).
112 * Otherwise, returns the smallest missing non-negative integer.
113 */
getNumNotIn(std::vector<int32_t> & nums)114 int32_t getNumNotIn(std::vector<int32_t>& nums) {
115 int32_t result = DEFAULT_ID;
116 int32_t size = static_cast<int32_t>(nums.size());
117 for (int32_t i = 0; i < size; i++) {
118 // Put every element to its target position, if possible.
119 int32_t target_pos = nums[i];
120 while (target_pos >= 0 && target_pos < size && i != target_pos &&
121 nums[i] != nums[target_pos]) {
122 std::swap(nums[i], nums[target_pos]);
123 target_pos = nums[i];
124 }
125 }
126
127 for (int32_t i = 0; i < size; i++) {
128 if (nums[i] != i) {
129 return i;
130 }
131 }
132 return result;
133 }
134
135 /* A simple test implementation of TvInputCallback for TV Input Events. */
136 class TvInputCallback : public ITvInputCallback {
137 public:
TvInputCallback(TvInputHidlTest & parent)138 TvInputCallback(TvInputHidlTest& parent) : parent_(parent){};
139
140 virtual ~TvInputCallback() = default;
141
142 /*
143 * Notifies the client that an event has occurred. For possible event types,
144 * check TvInputEventType.
145 */
notify(const TvInputEvent & event)146 Return<void> notify(const TvInputEvent& event) override {
147 std::unique_lock<std::mutex> lock(parent_.mutex_);
148 switch (event.type) {
149 case TvInputEventType::DEVICE_AVAILABLE:
150 parent_.onDeviceAvailable(event.deviceInfo);
151 break;
152 case TvInputEventType::DEVICE_UNAVAILABLE:
153 parent_.onDeviceUnavailable(event.deviceInfo.deviceId);
154 break;
155 case TvInputEventType::STREAM_CONFIGURATIONS_CHANGED:
156 parent_.onStreamConfigurationsChanged(event.deviceInfo.deviceId);
157 break;
158 }
159 return Void();
160 };
161
162 private:
163 /* The test contains this callback instance. */
164 TvInputHidlTest& parent_;
165 };
166
167 /* The TvInput used for the test. */
168 sp<ITvInput> tv_input_;
169
170 /* The TvInputCallback used for the test. */
171 sp<ITvInputCallback> tv_input_callback_;
172
173 /*
174 * A KeyedVector stores device information of every available device.
175 * A key is a device ID and the corresponding value is the TvInputDeviceInfo.
176 */
177 android::KeyedVector<int32_t, TvInputDeviceInfo> device_info_;
178
179 /*
180 * A KeyedVector stores a list of stream configurations of every available device.
181 * A key is a device ID and the corresponding value is the stream configuration list.
182 */
183 android::KeyedVector<int32_t, hidl_vec<TvStreamConfig>> stream_config_;
184
185 /* The mutex controls the access of shared data. */
186 std::mutex mutex_;
187 };
188
189 /*
190 * GetStreamConfigTest:
191 * Calls updateStreamConfigurations() for each existing device
192 * Checks returned results
193 */
TEST_P(TvInputHidlTest,GetStreamConfigTest)194 TEST_P(TvInputHidlTest, GetStreamConfigTest) {
195 std::unique_lock<std::mutex> lock(mutex_);
196 for (size_t i = 0; i < device_info_.size(); i++) {
197 int32_t device_id = device_info_.keyAt(i);
198 Result result = updateStreamConfigurations(device_id);
199 EXPECT_EQ(Result::OK, result);
200 }
201 }
202
203 /*
204 * OpenAndCloseStreamTest:
205 * Calls openStream() and then closeStream() for each existing stream
206 * Checks returned results
207 */
TEST_P(TvInputHidlTest,OpenAndCloseStreamTest)208 TEST_P(TvInputHidlTest, OpenAndCloseStreamTest) {
209 std::unique_lock<std::mutex> lock(mutex_);
210 updateAllStreamConfigurations();
211 for (size_t j = 0; j < stream_config_.size(); j++) {
212 int32_t device_id = stream_config_.keyAt(j);
213 hidl_vec<TvStreamConfig> config = stream_config_.valueAt(j);
214 for (size_t i = 0; i < config.size(); i++) {
215 Result result = Result::UNKNOWN;
216 int32_t stream_id = config[i].streamId;
217 tv_input_->openStream(device_id, stream_id,
218 [&result](Result res, const native_handle_t*) { result = res; });
219 EXPECT_EQ(Result::OK, result);
220
221 result = Result::UNKNOWN;
222 result = tv_input_->closeStream(device_id, stream_id);
223 EXPECT_EQ(Result::OK, result);
224 }
225 }
226 }
227
228 /*
229 * InvalidDeviceIdTest:
230 * Calls updateStreamConfigurations(), openStream(), and closeStream()
231 * for a non-existing device
232 * Checks returned results
233 * The results should be Result::INVALID_ARGUMENTS
234 */
TEST_P(TvInputHidlTest,InvalidDeviceIdTest)235 TEST_P(TvInputHidlTest, InvalidDeviceIdTest) {
236 std::unique_lock<std::mutex> lock(mutex_);
237
238 std::vector<int32_t> device_ids;
239 for (size_t i = 0; i < device_info_.size(); i++) {
240 device_ids.push_back(device_info_.keyAt(i));
241 }
242 // Get a non-existing device ID.
243 int32_t id = getNumNotIn(device_ids);
244 EXPECT_EQ(Result::INVALID_ARGUMENTS, updateStreamConfigurations(id));
245
246 Result result = Result::UNKNOWN;
247 int32_t stream_id = 0;
248 tv_input_->openStream(id, stream_id,
249 [&result](Result res, const native_handle_t*) { result = res; });
250 EXPECT_EQ(Result::INVALID_ARGUMENTS, result);
251
252 result = Result::UNKNOWN;
253 result = tv_input_->closeStream(id, stream_id);
254 EXPECT_EQ(Result::INVALID_ARGUMENTS, result);
255 }
256
257 /*
258 * InvalidStreamIdTest:
259 * Calls openStream(), and closeStream() for a non-existing stream
260 * Checks returned results
261 * The results should be Result::INVALID_ARGUMENTS
262 */
TEST_P(TvInputHidlTest,InvalidStreamIdTest)263 TEST_P(TvInputHidlTest, InvalidStreamIdTest) {
264 std::unique_lock<std::mutex> lock(mutex_);
265 if (device_info_.isEmpty()) {
266 return;
267 }
268 updateAllStreamConfigurations();
269
270 int32_t device_id = device_info_.keyAt(0);
271 // Get a non-existing stream ID.
272 int32_t id = DEFAULT_ID;
273 if (stream_config_.indexOfKey(device_id) >= 0) {
274 std::vector<int32_t> stream_ids;
275 hidl_vec<TvStreamConfig> config = stream_config_.valueFor(device_id);
276 for (size_t i = 0; i < config.size(); i++) {
277 stream_ids.push_back(config[i].streamId);
278 }
279 id = getNumNotIn(stream_ids);
280 }
281
282 Result result = Result::UNKNOWN;
283 tv_input_->openStream(device_id, id,
284 [&result](Result res, const native_handle_t*) { result = res; });
285 EXPECT_EQ(Result::INVALID_ARGUMENTS, result);
286
287 result = Result::UNKNOWN;
288 result = tv_input_->closeStream(device_id, id);
289 EXPECT_EQ(Result::INVALID_ARGUMENTS, result);
290 }
291
292 /*
293 * OpenAnOpenedStreamsTest:
294 * Calls openStream() twice for a stream (if any)
295 * Checks returned results
296 * The result of the second call should be Result::INVALID_STATE
297 */
TEST_P(TvInputHidlTest,OpenAnOpenedStreamsTest)298 TEST_P(TvInputHidlTest, OpenAnOpenedStreamsTest) {
299 std::unique_lock<std::mutex> lock(mutex_);
300 updateAllStreamConfigurations();
301 std::vector<size_t> indices = getConfigIndices();
302 if (indices.empty()) {
303 return;
304 }
305 int32_t device_id = stream_config_.keyAt(indices[0]);
306 int32_t stream_id = stream_config_.valueAt(indices[0])[0].streamId;
307
308 Result result = Result::UNKNOWN;
309 tv_input_->openStream(device_id, stream_id,
310 [&result](Result res, const native_handle_t*) { result = res; });
311 EXPECT_EQ(Result::OK, result);
312
313 tv_input_->openStream(device_id, stream_id,
314 [&result](Result res, const native_handle_t*) { result = res; });
315 EXPECT_EQ(Result::INVALID_STATE, result);
316
317 // close stream as subsequent tests assume no open streams
318 EXPECT_EQ(Result::OK, tv_input_->closeStream(device_id, stream_id));
319 }
320
321 /*
322 * CloseStreamBeforeOpenTest:
323 * Calls closeStream() without calling openStream() for a stream (if any)
324 * Checks the returned result
325 * The result should be Result::INVALID_STATE
326 */
TEST_P(TvInputHidlTest,CloseStreamBeforeOpenTest)327 TEST_P(TvInputHidlTest, CloseStreamBeforeOpenTest) {
328 std::unique_lock<std::mutex> lock(mutex_);
329 updateAllStreamConfigurations();
330 std::vector<size_t> indices = getConfigIndices();
331 if (indices.empty()) {
332 return;
333 }
334 int32_t device_id = stream_config_.keyAt(indices[0]);
335 int32_t stream_id = stream_config_.valueAt(indices[0])[0].streamId;
336 EXPECT_EQ(Result::INVALID_STATE, tv_input_->closeStream(device_id, stream_id));
337 }
338
339 INSTANTIATE_TEST_SUITE_P(
340 PerInstance, TvInputHidlTest,
341 testing::ValuesIn(android::hardware::getAllHalInstanceNames(ITvInput::descriptor)),
342 android::hardware::PrintInstanceNameToString);
343
344 // TODO remove from the allow list once the cf tv target is enabled for testing
345 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(TvInputHidlTest);
346