blob: 8d3395b8d21ae0b5fc8ac5e7208882cce8626833 [file] [log] [blame]
Yixiao Luoce501332022-08-12 11:18:18 -07001/*
2 * Copyright 2022 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#include "VtsHalTvInputTargetTest.h"
18
19#include <android-base/properties.h>
20#include <android/binder_ibinder.h>
21#include <android/binder_process.h>
22#include <android/binder_status.h>
23
24using namespace VtsHalTvInputTargetTest;
25
26TvInputAidlTest::TvInputCallback::TvInputCallback(shared_ptr<TvInputAidlTest> parent)
27 : parent_(parent) {}
28
29::ndk::ScopedAStatus TvInputAidlTest::TvInputCallback::notify(const TvInputEvent& in_event) {
30 unique_lock<mutex> lock(parent_->mutex_);
31
32 switch (in_event.type) {
33 case TvInputEventType::DEVICE_AVAILABLE:
34 parent_->onDeviceAvailable(in_event.deviceInfo);
35 break;
36 case TvInputEventType::DEVICE_UNAVAILABLE:
37 parent_->onDeviceUnavailable(in_event.deviceInfo.deviceId);
38 break;
39 case TvInputEventType::STREAM_CONFIGURATIONS_CHANGED:
40 parent_->onStreamConfigurationsChanged(in_event.deviceInfo.deviceId);
41 break;
42 }
43 return ::ndk::ScopedAStatus::ok();
44}
45
David Zhao6bdbc5e2023-01-12 16:51:03 -080046::ndk::ScopedAStatus TvInputAidlTest::TvInputCallback::notifyTvMessageEvent(
47 const TvMessageEvent& in_event) {
48 return ::ndk::ScopedAStatus::ok();
49}
50
Yixiao Luoce501332022-08-12 11:18:18 -070051void TvInputAidlTest::SetUp() {
52 if (AServiceManager_isDeclared(GetParam().c_str())) {
53 ::ndk::SpAIBinder binder(AServiceManager_waitForService(GetParam().c_str()));
54 tv_input_ = ITvInput::fromBinder(binder);
55 } else {
56 tv_input_ = nullptr;
57 }
58 ASSERT_NE(tv_input_, nullptr);
59
60 tv_input_callback_ =
61 ::ndk::SharedRefBase::make<TvInputCallback>(shared_ptr<TvInputAidlTest>(this));
62 ASSERT_NE(tv_input_callback_, nullptr);
63
64 tv_input_->setCallback(tv_input_callback_);
65 // All events received within the timeout should be handled.
66 sleep(WAIT_FOR_EVENT_TIMEOUT);
67}
68
69void TvInputAidlTest::TearDown() {
70 tv_input_ = nullptr;
71}
72
73void TvInputAidlTest::onDeviceAvailable(const TvInputDeviceInfo& deviceInfo) {
74 ALOGD("onDeviceAvailable for device id %d", deviceInfo.deviceId);
75 device_info_.add(deviceInfo.deviceId, deviceInfo);
76}
77
78void TvInputAidlTest::onDeviceUnavailable(int32_t deviceId) {
79 ALOGD("onDeviceUnavailable for device id %d", deviceId);
80 device_info_.removeItem(deviceId);
81 stream_config_.removeItem(deviceId);
82}
83
84::ndk::ScopedAStatus TvInputAidlTest::onStreamConfigurationsChanged(int32_t deviceId) {
85 ALOGD("onStreamConfigurationsChanged for device id %d", deviceId);
86 return updateStreamConfigurations(deviceId);
87}
88
89::ndk::ScopedAStatus TvInputAidlTest::updateStreamConfigurations(int32_t deviceId) {
90 stream_config_.removeItem(deviceId);
91 vector<TvStreamConfig> list;
92 ::ndk::ScopedAStatus status = tv_input_->getStreamConfigurations(deviceId, &list);
93 if (status.isOk()) {
94 stream_config_.add(deviceId, list);
95 }
96 return status;
97}
98
99void TvInputAidlTest::updateAllStreamConfigurations() {
100 for (size_t i = 0; i < device_info_.size(); i++) {
101 int32_t device_id = device_info_.keyAt(i);
102 updateStreamConfigurations(device_id);
103 }
104}
105
106vector<size_t> TvInputAidlTest::getConfigIndices() {
107 vector<size_t> indices;
108 for (size_t i = 0; i < stream_config_.size(); i++) {
109 if (stream_config_.valueAt(i).size() != 0) {
110 indices.push_back(i);
111 }
112 }
113 return indices;
114}
115
116int32_t TvInputAidlTest::getNumNotIn(vector<int32_t>& nums) {
117 int32_t result = DEFAULT_ID;
118 int32_t size = static_cast<int32_t>(nums.size());
119 for (int32_t i = 0; i < size; i++) {
120 // Put every element to its target position, if possible.
121 int32_t target_pos = nums[i];
122 while (target_pos >= 0 && target_pos < size && i != target_pos &&
123 nums[i] != nums[target_pos]) {
124 swap(nums[i], nums[target_pos]);
125 target_pos = nums[i];
126 }
127 }
128
129 for (int32_t i = 0; i < size; i++) {
130 if (nums[i] != i) {
131 return i;
132 }
133 }
134 return result;
135}
136
Yixiao Luod6976522023-05-26 15:24:03 -0700137bool TvInputAidlTest::isValidHandle(NativeHandle& handle) {
138 if (handle.fds.empty()) {
139 return false;
140 }
141 for (size_t i = 0; i < handle.fds.size(); i++) {
142 int fd = handle.fds[i].get();
143 if (fcntl(fd, F_GETFL) < 0) {
144 return false;
145 }
146 }
147 return true;
148}
149
Yixiao Luoce501332022-08-12 11:18:18 -0700150/*
151 * GetStreamConfigTest:
152 * Calls updateStreamConfigurations() for each existing device
153 * Checks returned results
154 */
155TEST_P(TvInputAidlTest, GetStreamConfigTest) {
156 unique_lock<mutex> lock(mutex_);
157
158 for (size_t i = 0; i < device_info_.size(); i++) {
159 int32_t device_id = device_info_.keyAt(i);
160 ALOGD("GetStreamConfigTest: device_id=%d", device_id);
161 ASSERT_TRUE(updateStreamConfigurations(device_id).isOk());
162 }
163}
164
165/*
166 * OpenAndCloseStreamTest:
167 * Calls openStream() and then closeStream() for each existing stream
168 * Checks returned results
169 */
170TEST_P(TvInputAidlTest, OpenAndCloseStreamTest) {
171 unique_lock<mutex> lock(mutex_);
172
173 updateAllStreamConfigurations();
174
175 for (size_t j = 0; j < stream_config_.size(); j++) {
176 int32_t device_id = stream_config_.keyAt(j);
177 vector<TvStreamConfig> config = stream_config_.valueAt(j);
178 for (size_t i = 0; i < config.size(); i++) {
Yixiao Luo4cd52a92022-10-28 15:51:48 -0700179 NativeHandle handle;
Yixiao Luoce501332022-08-12 11:18:18 -0700180 int32_t stream_id = config[i].streamId;
181 ALOGD("OpenAndCloseStreamTest: open stream, device_id=%d, stream_id=%d", device_id,
182 stream_id);
Yixiao Luo4cd52a92022-10-28 15:51:48 -0700183 ASSERT_TRUE(tv_input_->openStream(device_id, stream_id, &handle).isOk());
Yixiao Luod6976522023-05-26 15:24:03 -0700184 ASSERT_TRUE(isValidHandle(handle));
185
Yixiao Luoce501332022-08-12 11:18:18 -0700186 ALOGD("OpenAndCloseStreamTest: close stream, device_id=%d, stream_id=%d", device_id,
187 stream_id);
188 ASSERT_TRUE(tv_input_->closeStream(device_id, stream_id).isOk());
189 }
190 }
191}
192
193/*
194 * InvalidDeviceIdTest:
195 * Calls updateStreamConfigurations(), openStream(), and closeStream()
196 * for a non-existing device
197 * Checks returned results
198 * The results should be ITvInput::STATUS_INVALID_ARGUMENTS
199 */
200TEST_P(TvInputAidlTest, InvalidDeviceIdTest) {
201 unique_lock<mutex> lock(mutex_);
202
203 vector<int32_t> device_ids;
204 for (size_t i = 0; i < device_info_.size(); i++) {
205 device_ids.push_back(device_info_.keyAt(i));
206 }
207 // Get a non-existing device ID.
208 int32_t id = getNumNotIn(device_ids);
209 ALOGD("InvalidDeviceIdTest: update stream config, device_id=%d", id);
210 ASSERT_TRUE(updateStreamConfigurations(id).getServiceSpecificError() ==
211 ITvInput::STATUS_INVALID_ARGUMENTS);
212
213 int32_t stream_id = 0;
Yixiao Luo4cd52a92022-10-28 15:51:48 -0700214 NativeHandle handle;
Yixiao Luoce501332022-08-12 11:18:18 -0700215
216 ALOGD("InvalidDeviceIdTest: open stream, device_id=%d, stream_id=%d", id, stream_id);
Yixiao Luo4cd52a92022-10-28 15:51:48 -0700217 ASSERT_TRUE(tv_input_->openStream(id, stream_id, &handle).getServiceSpecificError() ==
Yixiao Luoce501332022-08-12 11:18:18 -0700218 ITvInput::STATUS_INVALID_ARGUMENTS);
219
220 ALOGD("InvalidDeviceIdTest: close stream, device_id=%d, stream_id=%d", id, stream_id);
221 ASSERT_TRUE(tv_input_->closeStream(id, stream_id).getServiceSpecificError() ==
222 ITvInput::STATUS_INVALID_ARGUMENTS);
223}
224
225/*
226 * InvalidStreamIdTest:
227 * Calls openStream(), and closeStream() for a non-existing stream
228 * Checks returned results
229 * The results should be ITvInput::STATUS_INVALID_ARGUMENTS
230 */
231TEST_P(TvInputAidlTest, InvalidStreamIdTest) {
232 unique_lock<mutex> lock(mutex_);
233
234 if (device_info_.isEmpty()) {
235 return;
236 }
237 updateAllStreamConfigurations();
238
239 int32_t device_id = device_info_.keyAt(0);
240 // Get a non-existing stream ID.
241 int32_t id = DEFAULT_ID;
242 if (stream_config_.indexOfKey(device_id) >= 0) {
243 vector<int32_t> stream_ids;
244 vector<TvStreamConfig> config = stream_config_.valueFor(device_id);
245 for (size_t i = 0; i < config.size(); i++) {
246 stream_ids.push_back(config[i].streamId);
247 }
248 id = getNumNotIn(stream_ids);
249 }
250
Yixiao Luo4cd52a92022-10-28 15:51:48 -0700251 NativeHandle handle;
252
Yixiao Luoce501332022-08-12 11:18:18 -0700253 ALOGD("InvalidStreamIdTest: open stream, device_id=%d, stream_id=%d", device_id, id);
Yixiao Luo4cd52a92022-10-28 15:51:48 -0700254 ASSERT_TRUE(tv_input_->openStream(device_id, id, &handle).getServiceSpecificError() ==
Yixiao Luoce501332022-08-12 11:18:18 -0700255 ITvInput::STATUS_INVALID_ARGUMENTS);
256
257 ALOGD("InvalidStreamIdTest: close stream, device_id=%d, stream_id=%d", device_id, id);
258 ASSERT_TRUE(tv_input_->closeStream(device_id, id).getServiceSpecificError() ==
259 ITvInput::STATUS_INVALID_ARGUMENTS);
260}
261
262/*
263 * OpenAnOpenedStreamsTest:
264 * Calls openStream() twice for a stream (if any)
265 * Checks returned results
266 * The result of the second call should be ITvInput::STATUS_INVALID_STATE
267 */
268TEST_P(TvInputAidlTest, OpenAnOpenedStreamsTest) {
269 unique_lock<mutex> lock(mutex_);
270
271 updateAllStreamConfigurations();
272 vector<size_t> indices = getConfigIndices();
273 if (indices.empty()) {
274 return;
275 }
276 int32_t device_id = stream_config_.keyAt(indices[0]);
David Zhao17a91902023-05-17 16:36:38 -0700277 vector<TvStreamConfig> streamConfigs = stream_config_.valueAt(indices[0]);
278 if (streamConfigs.empty()) {
279 return;
280 }
281 int32_t stream_id = streamConfigs[0].streamId;
Yixiao Luo4cd52a92022-10-28 15:51:48 -0700282 NativeHandle handle;
Yixiao Luoce501332022-08-12 11:18:18 -0700283
284 ALOGD("OpenAnOpenedStreamsTest: open stream, device_id=%d, stream_id=%d", device_id, stream_id);
Yixiao Luo4cd52a92022-10-28 15:51:48 -0700285 ASSERT_TRUE(tv_input_->openStream(device_id, stream_id, &handle).isOk());
Yixiao Luod6976522023-05-26 15:24:03 -0700286 ASSERT_TRUE(isValidHandle(handle));
Yixiao Luo4cd52a92022-10-28 15:51:48 -0700287
288 ALOGD("OpenAnOpenedStreamsTest: open stream, device_id=%d, stream_id=%d", device_id, stream_id);
289 ASSERT_TRUE(tv_input_->openStream(device_id, stream_id, &handle).getServiceSpecificError() ==
Yixiao Luoce501332022-08-12 11:18:18 -0700290 ITvInput::STATUS_INVALID_STATE);
291
292 // close stream as subsequent tests assume no open streams
293 ALOGD("OpenAnOpenedStreamsTest: close stream, device_id=%d, stream_id=%d", device_id,
294 stream_id);
295 ASSERT_TRUE(tv_input_->closeStream(device_id, stream_id).isOk());
296}
297
298/*
299 * CloseStreamBeforeOpenTest:
300 * Calls closeStream() without calling openStream() for a stream (if any)
301 * Checks the returned result
302 * The result should be ITvInput::STATUS_INVALID_STATE
303 */
304TEST_P(TvInputAidlTest, CloseStreamBeforeOpenTest) {
305 unique_lock<mutex> lock(mutex_);
306
307 updateAllStreamConfigurations();
308 vector<size_t> indices = getConfigIndices();
309 if (indices.empty()) {
310 return;
311 }
312 int32_t device_id = stream_config_.keyAt(indices[0]);
David Zhao17a91902023-05-17 16:36:38 -0700313 vector<TvStreamConfig> streamConfigs = stream_config_.valueAt(indices[0]);
314 if (streamConfigs.empty()) {
315 return;
316 }
317 int32_t stream_id = streamConfigs[0].streamId;
Yixiao Luoce501332022-08-12 11:18:18 -0700318
319 ALOGD("CloseStreamBeforeOpenTest: close stream, device_id=%d, stream_id=%d", device_id,
320 stream_id);
321 ASSERT_TRUE(tv_input_->closeStream(device_id, stream_id).getServiceSpecificError() ==
322 ITvInput::STATUS_INVALID_STATE);
323}
324
David Zhao17a91902023-05-17 16:36:38 -0700325TEST_P(TvInputAidlTest, SetTvMessageEnabledTest) {
326 unique_lock<mutex> lock(mutex_);
327
328 updateAllStreamConfigurations();
329 vector<size_t> indices = getConfigIndices();
330 if (indices.empty()) {
331 return;
332 }
333 int32_t device_id = stream_config_.keyAt(indices[0]);
334 vector<TvStreamConfig> streamConfigs = stream_config_.valueAt(indices[0]);
335 if (streamConfigs.empty()) {
336 return;
337 }
338 int32_t stream_id = streamConfigs[0].streamId;
339 ALOGD("SetTvMessageEnabledTest: device_id=%d, stream_id=%d", device_id, stream_id);
340 tv_input_->setTvMessageEnabled(device_id, stream_id, TvMessageEventType::WATERMARK, true);
341}
342
343TEST_P(TvInputAidlTest, GetTvMessageQueueTest) {
344 unique_lock<mutex> lock(mutex_);
345
346 updateAllStreamConfigurations();
347 vector<size_t> indices = getConfigIndices();
348 if (indices.empty()) {
349 return;
350 }
351 int32_t device_id = stream_config_.keyAt(indices[0]);
352 vector<TvStreamConfig> streamConfigs = stream_config_.valueAt(indices[0]);
353 if (streamConfigs.empty()) {
354 return;
355 }
356 int32_t stream_id = streamConfigs[0].streamId;
357 ALOGD("GetTvMessageQueueTest: device_id=%d, stream_id=%d", device_id, stream_id);
358 MQDescriptor<int8_t, SynchronizedReadWrite> queue;
359 tv_input_->getTvMessageQueueDesc(&queue, device_id, stream_id);
360}
361
Yixiao Luoce501332022-08-12 11:18:18 -0700362INSTANTIATE_TEST_SUITE_P(PerInstance, TvInputAidlTest,
363 testing::ValuesIn(android::getAidlHalInstanceNames(ITvInput::descriptor)),
364 android::PrintInstanceNameToString);
365
366// TODO remove from the allow list once the cf tv target is enabled for testing
367GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(TvInputAidlTest);