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