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/types.h>
21 #include <android/hardware/tv/input/1.0/ITvInput.h>
22 #include <android/hardware/tv/input/1.0/ITvInputCallback.h>
23
24 #include <VtsHalHidlTargetTestBase.h>
25 #include <utils/KeyedVector.h>
26 #include <mutex>
27 #include <vector>
28
29 using ::android::hardware::tv::input::V1_0::ITvInput;
30 using ::android::hardware::tv::input::V1_0::ITvInputCallback;
31 using ::android::hardware::tv::input::V1_0::Result;
32 using ::android::hardware::tv::input::V1_0::TvInputType;
33 using ::android::hardware::tv::input::V1_0::TvInputDeviceInfo;
34 using ::android::hardware::tv::input::V1_0::TvInputEventType;
35 using ::android::hardware::tv::input::V1_0::TvInputEvent;
36 using ::android::hardware::tv::input::V1_0::TvStreamConfig;
37 using ::android::hardware::Return;
38 using ::android::hardware::Void;
39 using ::android::hardware::hidl_vec;
40 using ::android::sp;
41
42 #define WAIT_FOR_EVENT_TIMEOUT 5
43 #define DEFAULT_ID INT32_MIN
44
45 // Test environment for TvInput HIDL HAL.
46 class TvInputHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
47 public:
48 // get the test environment singleton
Instance()49 static TvInputHidlEnvironment* Instance() {
50 static TvInputHidlEnvironment* instance = new TvInputHidlEnvironment;
51 return instance;
52 }
53
registerTestServices()54 virtual void registerTestServices() override { registerTestService<ITvInput>(); }
55
56 private:
TvInputHidlEnvironment()57 TvInputHidlEnvironment() {}
58 };
59
60 /* The main test class for TV Input HIDL HAL. */
61 class TvInputHidlTest : public ::testing::VtsHalHidlTargetTestBase {
62 public:
SetUp()63 virtual void SetUp() override {
64 tv_input_ = ::testing::VtsHalHidlTargetTestBase::getService<ITvInput>(
65 TvInputHidlEnvironment::Instance()->getServiceName<ITvInput>());
66 ASSERT_NE(tv_input_, nullptr);
67 tv_input_callback_ = new TvInputCallback(*this);
68 ASSERT_NE(tv_input_callback_, nullptr);
69 tv_input_->setCallback(tv_input_callback_);
70 // All events received within the timeout should be handled.
71 sleep(WAIT_FOR_EVENT_TIMEOUT);
72 }
73
TearDown()74 virtual void TearDown() override {}
75
76 /* Called when a DEVICE_AVAILABLE event is received. */
onDeviceAvailable(const TvInputDeviceInfo & deviceInfo)77 void onDeviceAvailable(const TvInputDeviceInfo& deviceInfo) {
78 device_info_.add(deviceInfo.deviceId, deviceInfo);
79 }
80
81 /* Called when a DEVICE_UNAVAILABLE event is received. */
onDeviceUnavailable(int32_t deviceId)82 void onDeviceUnavailable(int32_t deviceId) {
83 device_info_.removeItem(deviceId);
84 }
85
86 /* Called when a DEVICE_CONFIGURATIONS_CHANGED event is received. */
onStreamConfigurationsChanged(int32_t deviceId)87 Result onStreamConfigurationsChanged(int32_t deviceId) {
88 return updateStreamConfigurations(deviceId);
89 }
90
91 /* Gets and updates the stream configurations for a device. */
updateStreamConfigurations(int32_t deviceId)92 Result updateStreamConfigurations(int32_t deviceId) {
93 stream_config_.removeItem(deviceId);
94 Result result = Result::UNKNOWN;
95 hidl_vec<TvStreamConfig> list;
96 tv_input_->getStreamConfigurations(deviceId,
97 [&result, &list](Result res, hidl_vec<TvStreamConfig> configs) {
98 result = res;
99 if (res == Result::OK) {
100 list = configs;
101 }
102 });
103 if (result == Result::OK) {
104 stream_config_.add(deviceId, list);
105 }
106 return result;
107 }
108
109 /* Gets and updates the stream configurations for all existing devices. */
updateAllStreamConfigurations()110 void updateAllStreamConfigurations() {
111 for (size_t i = 0; i < device_info_.size(); i++) {
112 int32_t device_id = device_info_.keyAt(i);
113 updateStreamConfigurations(device_id);
114 }
115 }
116
117 /* Returns a list of indices of stream_config_ whose corresponding values are not empty. */
getConfigIndices()118 std::vector<size_t> getConfigIndices() {
119 std::vector<size_t> indices;
120 for (size_t i = 0; i < stream_config_.size(); i++) {
121 if (stream_config_.valueAt(i).size() != 0) {
122 indices.push_back(i);
123 }
124 }
125 return indices;
126 }
127
128 /*
129 * Returns DEFAULT_ID if there is no missing integer in the range [0, the size of nums).
130 * Otherwise, returns the smallest missing non-negative integer.
131 */
getNumNotIn(std::vector<int32_t> & nums)132 int32_t getNumNotIn(std::vector<int32_t>& nums) {
133 int32_t result = DEFAULT_ID;
134 int32_t size = static_cast<int32_t>(nums.size());
135 for (int32_t i = 0; i < size; i++) {
136 // Put every element to its target position, if possible.
137 int32_t target_pos = nums[i];
138 while (target_pos >= 0 && target_pos < size && i != target_pos && nums[i] != nums[target_pos]) {
139 std::swap(nums[i], nums[target_pos]);
140 target_pos = nums[i];
141 }
142 }
143
144 for (int32_t i = 0; i < size; i++) {
145 if (nums[i] != i) {
146 return i;
147 }
148 }
149 return result;
150 }
151
152 /* A simple test implementation of TvInputCallback for TV Input Events. */
153 class TvInputCallback : public ITvInputCallback {
154 public:
TvInputCallback(TvInputHidlTest & parent)155 TvInputCallback(TvInputHidlTest& parent) : parent_(parent){};
156
157 virtual ~TvInputCallback() = default;
158
159 /*
160 * Notifies the client that an event has occured. For possible event types,
161 * check TvInputEventType.
162 */
notify(const TvInputEvent & event)163 Return<void> notify(const TvInputEvent& event) override {
164 std::unique_lock<std::mutex> lock(parent_.mutex_);
165 switch(event.type) {
166 case TvInputEventType::DEVICE_AVAILABLE:
167 parent_.onDeviceAvailable(event.deviceInfo);
168 break;
169 case TvInputEventType::DEVICE_UNAVAILABLE:
170 parent_.onDeviceUnavailable(event.deviceInfo.deviceId);
171 break;
172 case TvInputEventType::STREAM_CONFIGURATIONS_CHANGED:
173 parent_.onStreamConfigurationsChanged(event.deviceInfo.deviceId);
174 break;
175 }
176 return Void();
177 };
178 private:
179 /* The test contains this callback instance. */
180 TvInputHidlTest& parent_;
181 };
182
183 /* The TvInput used for the test. */
184 sp<ITvInput> tv_input_;
185
186 /* The TvInputCallback used for the test. */
187 sp<ITvInputCallback> tv_input_callback_;
188
189 /*
190 * A KeyedVector stores device information of every available device.
191 * A key is a device ID and the corresponding value is the TvInputDeviceInfo.
192 */
193 android::KeyedVector<int32_t, TvInputDeviceInfo> device_info_;
194
195 /*
196 * A KeyedVector stores a list of stream configurations of every available device.
197 * A key is a device ID and the corresponding value is the stream configuration list.
198 */
199 android::KeyedVector<int32_t, hidl_vec<TvStreamConfig>> stream_config_;
200
201 /* The mutex controls the access of shared data. */
202 std::mutex mutex_;
203 };
204
205
206 /*
207 * GetStreamConfigTest:
208 * Calls updateStreamConfigurations() for each existing device
209 * Checks returned results
210 */
TEST_F(TvInputHidlTest,GetStreamConfigTest)211 TEST_F(TvInputHidlTest, GetStreamConfigTest) {
212 std::unique_lock<std::mutex> lock(mutex_);
213 for (size_t i = 0; i < device_info_.size(); i++) {
214 int32_t device_id = device_info_.keyAt(i);
215 Result result = updateStreamConfigurations(device_id);
216 EXPECT_EQ(Result::OK, result);
217 }
218 }
219
220 /*
221 * OpenAndCloseStreamTest:
222 * Calls openStream() and then closeStream() for each existing stream
223 * Checks returned results
224 */
TEST_F(TvInputHidlTest,OpenAndCloseStreamTest)225 TEST_F(TvInputHidlTest, OpenAndCloseStreamTest) {
226 std::unique_lock<std::mutex> lock(mutex_);
227 updateAllStreamConfigurations();
228 for (size_t j = 0; j < stream_config_.size(); j++) {
229 int32_t device_id = stream_config_.keyAt(j);
230 hidl_vec<TvStreamConfig> config = stream_config_.valueAt(j);
231 for (size_t i = 0; i < config.size(); i++) {
232 Result result = Result::UNKNOWN;
233 int32_t stream_id = config[i].streamId;
234 tv_input_->openStream(device_id, stream_id,
235 [&result](Result res, const native_handle_t*) {
236 result = res;
237 });
238 EXPECT_EQ(Result::OK, result);
239
240 result = Result::UNKNOWN;
241 result = tv_input_->closeStream(device_id, stream_id);
242 EXPECT_EQ(Result::OK, result);
243 }
244 }
245 }
246
247 /*
248 * InvalidDeviceIdTest:
249 * Calls updateStreamConfigurations(), openStream(), and closeStream()
250 * for a non-existing device
251 * Checks returned results
252 * The results should be Result::INVALID_ARGUMENTS
253 */
TEST_F(TvInputHidlTest,InvalidDeviceIdTest)254 TEST_F(TvInputHidlTest, InvalidDeviceIdTest) {
255 std::unique_lock<std::mutex> lock(mutex_);
256
257 std::vector<int32_t> device_ids;
258 for (size_t i = 0; i < device_info_.size(); i++) {
259 device_ids.push_back(device_info_.keyAt(i));
260 }
261 // Get a non-existing device ID.
262 int32_t id = getNumNotIn(device_ids);
263 EXPECT_EQ(Result::INVALID_ARGUMENTS, updateStreamConfigurations(id));
264
265 Result result = Result::UNKNOWN;
266 int32_t stream_id = 0;
267 tv_input_->openStream(id, stream_id,
268 [&result](Result res, const native_handle_t*) {
269 result = res;
270 });
271 EXPECT_EQ(Result::INVALID_ARGUMENTS, result);
272
273 result = Result::UNKNOWN;
274 result = tv_input_->closeStream(id, stream_id);
275 EXPECT_EQ(Result::INVALID_ARGUMENTS, result);
276 }
277
278 /*
279 * InvalidStreamIdTest:
280 * Calls openStream(), and closeStream() for a non-existing stream
281 * Checks returned results
282 * The results should be Result::INVALID_ARGUMENTS
283 */
TEST_F(TvInputHidlTest,InvalidStreamIdTest)284 TEST_F(TvInputHidlTest, InvalidStreamIdTest) {
285 std::unique_lock<std::mutex> lock(mutex_);
286 if (device_info_.isEmpty()) {
287 return;
288 }
289 updateAllStreamConfigurations();
290
291 int32_t device_id = device_info_.keyAt(0);
292 // Get a non-existing stream ID.
293 int32_t id = DEFAULT_ID;
294 if (stream_config_.indexOfKey(device_id) >= 0) {
295 std::vector<int32_t> stream_ids;
296 hidl_vec<TvStreamConfig> config = stream_config_.valueFor(device_id);
297 for (size_t i = 0; i < config.size(); i++) {
298 stream_ids.push_back(config[i].streamId);
299 }
300 id = getNumNotIn(stream_ids);
301 }
302
303 Result result = Result::UNKNOWN;
304 tv_input_->openStream(device_id, id,
305 [&result](Result res, const native_handle_t*) {
306 result = res;
307 });
308 EXPECT_EQ(Result::INVALID_ARGUMENTS, result);
309
310 result = Result::UNKNOWN;
311 result = tv_input_->closeStream(device_id, id);
312 EXPECT_EQ(Result::INVALID_ARGUMENTS, result);
313 }
314
315 /*
316 * OpenAnOpenedStreamsTest:
317 * Calls openStream() twice for a stream (if any)
318 * Checks returned results
319 * The result of the second call should be Result::INVALID_STATE
320 */
TEST_F(TvInputHidlTest,OpenAnOpenedStreamsTest)321 TEST_F(TvInputHidlTest, OpenAnOpenedStreamsTest) {
322 std::unique_lock<std::mutex> lock(mutex_);
323 updateAllStreamConfigurations();
324 std::vector<size_t> indices = getConfigIndices();
325 if (indices.empty()) {
326 return;
327 }
328 int32_t device_id = stream_config_.keyAt(indices[0]);
329 int32_t stream_id = stream_config_.valueAt(indices[0])[0].streamId;
330
331 Result result = Result::UNKNOWN;
332 tv_input_->openStream(device_id, stream_id,
333 [&result](Result res, const native_handle_t*) {
334 result = res;
335 });
336 EXPECT_EQ(Result::OK, result);
337
338 tv_input_->openStream(device_id, stream_id,
339 [&result](Result res, const native_handle_t*) {
340 result = res;
341 });
342 EXPECT_EQ(Result::INVALID_STATE, result);
343 }
344
345 /*
346 * CloseStreamBeforeOpenTest:
347 * Calls closeStream() without calling openStream() for a stream (if any)
348 * Checks the returned result
349 * The result should be Result::INVALID_STATE
350 */
TEST_F(TvInputHidlTest,CloseStreamBeforeOpenTest)351 TEST_F(TvInputHidlTest, CloseStreamBeforeOpenTest) {
352 std::unique_lock<std::mutex> lock(mutex_);
353 updateAllStreamConfigurations();
354 std::vector<size_t> indices = getConfigIndices();
355 if (indices.empty()) {
356 return;
357 }
358 int32_t device_id = stream_config_.keyAt(indices[0]);
359 int32_t stream_id = stream_config_.valueAt(indices[0])[0].streamId;
360 EXPECT_EQ(Result::INVALID_STATE, tv_input_->closeStream(device_id, stream_id));
361 }
362
main(int argc,char ** argv)363 int main(int argc, char **argv) {
364 ::testing::AddGlobalTestEnvironment(TvInputHidlEnvironment::Instance());
365 ::testing::InitGoogleTest(&argc, argv);
366 TvInputHidlEnvironment::Instance()->init(&argc, argv);
367 int status = RUN_ALL_TESTS();
368 ALOGI("Test result = %d", status);
369 return status;
370 }
371
372