xref: /aosp_15_r20/hardware/interfaces/tv/input/aidl/vts/functional/VtsHalTvInputTargetTest.cpp (revision 4d7e907c777eeecc4c5bd7cf640a754fac206ff7)
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