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 /* The main test class for TV Input HIDL HAL. */
46 class TvInputHidlTest : public ::testing::VtsHalHidlTargetTestBase {
47 public:
SetUp()48 virtual void SetUp() override {
49 tv_input_ = ::testing::VtsHalHidlTargetTestBase::getService<ITvInput>();
50 ASSERT_NE(tv_input_, nullptr);
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) {
67 device_info_.removeItem(deviceId);
68 }
69
70 /* Called when a DEVICE_CONFIGURATIONS_CHANGED event is received. */
onStreamConfigurationsChanged(int32_t deviceId)71 Result onStreamConfigurationsChanged(int32_t deviceId) {
72 return updateStreamConfigurations(deviceId);
73 }
74
75 /* Gets and updates the stream configurations for a device. */
updateStreamConfigurations(int32_t deviceId)76 Result updateStreamConfigurations(int32_t deviceId) {
77 stream_config_.removeItem(deviceId);
78 Result result = Result::UNKNOWN;
79 hidl_vec<TvStreamConfig> list;
80 tv_input_->getStreamConfigurations(deviceId,
81 [&result, &list](Result res, hidl_vec<TvStreamConfig> configs) {
82 result = res;
83 if (res == Result::OK) {
84 list = configs;
85 }
86 });
87 if (result == Result::OK) {
88 stream_config_.add(deviceId, list);
89 }
90 return result;
91 }
92
93 /* Gets and updates the stream configurations for all existing devices. */
updateAllStreamConfigurations()94 void updateAllStreamConfigurations() {
95 for (size_t i = 0; i < device_info_.size(); i++) {
96 int32_t device_id = device_info_.keyAt(i);
97 updateStreamConfigurations(device_id);
98 }
99 }
100
101 /* Returns a list of indices of stream_config_ whose corresponding values are not empty. */
getConfigIndices()102 std::vector<size_t> getConfigIndices() {
103 std::vector<size_t> indices;
104 for (size_t i = 0; i < stream_config_.size(); i++) {
105 if (stream_config_.valueAt(i).size() != 0) {
106 indices.push_back(i);
107 }
108 }
109 return indices;
110 }
111
112 /*
113 * Returns DEFAULT_ID if there is no missing integer in the range [0, the size of nums).
114 * Otherwise, returns the smallest missing non-negative integer.
115 */
getNumNotIn(std::vector<int32_t> & nums)116 int32_t getNumNotIn(std::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 && nums[i] != nums[target_pos]) {
123 std::swap(nums[i], nums[target_pos]);
124 target_pos = nums[i];
125 }
126 }
127
128 for (int32_t i = 0; i < size; i++) {
129 if (nums[i] != i) {
130 return i;
131 }
132 }
133 return result;
134 }
135
136 /* A simple test implementation of TvInputCallback for TV Input Events. */
137 class TvInputCallback : public ITvInputCallback {
138 public:
TvInputCallback(TvInputHidlTest & parent)139 TvInputCallback(TvInputHidlTest& parent) : parent_(parent){};
140
141 virtual ~TvInputCallback() = default;
142
143 /*
144 * Notifies the client that an event has occured. For possible event types,
145 * check TvInputEventType.
146 */
notify(const TvInputEvent & event)147 Return<void> notify(const TvInputEvent& event) override {
148 std::unique_lock<std::mutex> lock(parent_.mutex_);
149 switch(event.type) {
150 case TvInputEventType::DEVICE_AVAILABLE:
151 parent_.onDeviceAvailable(event.deviceInfo);
152 break;
153 case TvInputEventType::DEVICE_UNAVAILABLE:
154 parent_.onDeviceUnavailable(event.deviceInfo.deviceId);
155 break;
156 case TvInputEventType::STREAM_CONFIGURATIONS_CHANGED:
157 parent_.onStreamConfigurationsChanged(event.deviceInfo.deviceId);
158 break;
159 }
160 return Void();
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 /* A class for test environment setup. */
191 class TvInputHidlEnvironment : public ::testing::Environment {
192 public:
SetUp()193 virtual void SetUp() {}
TearDown()194 virtual void TearDown() {}
195
196 private:
197 };
198
199 /*
200 * GetStreamConfigTest:
201 * Calls updateStreamConfigurations() for each existing device
202 * Checks returned results
203 */
TEST_F(TvInputHidlTest,GetStreamConfigTest)204 TEST_F(TvInputHidlTest, GetStreamConfigTest) {
205 std::unique_lock<std::mutex> lock(mutex_);
206 for (size_t i = 0; i < device_info_.size(); i++) {
207 int32_t device_id = device_info_.keyAt(i);
208 Result result = updateStreamConfigurations(device_id);
209 EXPECT_EQ(Result::OK, result);
210 }
211 }
212
213 /*
214 * OpenAndCloseStreamTest:
215 * Calls openStream() and then closeStream() for each existing stream
216 * Checks returned results
217 */
TEST_F(TvInputHidlTest,OpenAndCloseStreamTest)218 TEST_F(TvInputHidlTest, OpenAndCloseStreamTest) {
219 std::unique_lock<std::mutex> lock(mutex_);
220 updateAllStreamConfigurations();
221 for (size_t j = 0; j < stream_config_.size(); j++) {
222 int32_t device_id = stream_config_.keyAt(j);
223 hidl_vec<TvStreamConfig> config = stream_config_.valueAt(j);
224 for (size_t i = 0; i < config.size(); i++) {
225 Result result = Result::UNKNOWN;
226 int32_t stream_id = config[i].streamId;
227 tv_input_->openStream(device_id, stream_id,
228 [&result](Result res, const native_handle_t*) {
229 result = res;
230 });
231 EXPECT_EQ(Result::OK, result);
232
233 result = Result::UNKNOWN;
234 result = tv_input_->closeStream(device_id, stream_id);
235 EXPECT_EQ(Result::OK, result);
236 }
237 }
238 }
239
240 /*
241 * InvalidDeviceIdTest:
242 * Calls updateStreamConfigurations(), openStream(), and closeStream()
243 * for a non-existing device
244 * Checks returned results
245 * The results should be Result::INVALID_ARGUMENTS
246 */
TEST_F(TvInputHidlTest,InvalidDeviceIdTest)247 TEST_F(TvInputHidlTest, InvalidDeviceIdTest) {
248 std::unique_lock<std::mutex> lock(mutex_);
249
250 std::vector<int32_t> device_ids;
251 for (size_t i = 0; i < device_info_.size(); i++) {
252 device_ids.push_back(device_info_.keyAt(i));
253 }
254 // Get a non-existing device ID.
255 int32_t id = getNumNotIn(device_ids);
256 EXPECT_EQ(Result::INVALID_ARGUMENTS, updateStreamConfigurations(id));
257
258 Result result = Result::UNKNOWN;
259 int32_t stream_id = 0;
260 tv_input_->openStream(id, stream_id,
261 [&result](Result res, const native_handle_t*) {
262 result = res;
263 });
264 EXPECT_EQ(Result::INVALID_ARGUMENTS, result);
265
266 result = Result::UNKNOWN;
267 result = tv_input_->closeStream(id, stream_id);
268 EXPECT_EQ(Result::INVALID_ARGUMENTS, result);
269 }
270
271 /*
272 * InvalidStreamIdTest:
273 * Calls openStream(), and closeStream() for a non-existing stream
274 * Checks returned results
275 * The results should be Result::INVALID_ARGUMENTS
276 */
TEST_F(TvInputHidlTest,InvalidStreamIdTest)277 TEST_F(TvInputHidlTest, InvalidStreamIdTest) {
278 std::unique_lock<std::mutex> lock(mutex_);
279 if (device_info_.isEmpty()) {
280 return;
281 }
282 updateAllStreamConfigurations();
283
284 int32_t device_id = device_info_.keyAt(0);
285 // Get a non-existing stream ID.
286 int32_t id = DEFAULT_ID;
287 if (stream_config_.indexOfKey(device_id) >= 0) {
288 std::vector<int32_t> stream_ids;
289 hidl_vec<TvStreamConfig> config = stream_config_.valueFor(device_id);
290 for (size_t i = 0; i < config.size(); i++) {
291 stream_ids.push_back(config[i].streamId);
292 }
293 id = getNumNotIn(stream_ids);
294 }
295
296 Result result = Result::UNKNOWN;
297 tv_input_->openStream(device_id, id,
298 [&result](Result res, const native_handle_t*) {
299 result = res;
300 });
301 EXPECT_EQ(Result::INVALID_ARGUMENTS, result);
302
303 result = Result::UNKNOWN;
304 result = tv_input_->closeStream(device_id, id);
305 EXPECT_EQ(Result::INVALID_ARGUMENTS, result);
306 }
307
308 /*
309 * OpenAnOpenedStreamsTest:
310 * Calls openStream() twice for a stream (if any)
311 * Checks returned results
312 * The result of the second call should be Result::INVALID_STATE
313 */
TEST_F(TvInputHidlTest,OpenAnOpenedStreamsTest)314 TEST_F(TvInputHidlTest, OpenAnOpenedStreamsTest) {
315 std::unique_lock<std::mutex> lock(mutex_);
316 updateAllStreamConfigurations();
317 std::vector<size_t> indices = getConfigIndices();
318 if (indices.empty()) {
319 return;
320 }
321 int32_t device_id = stream_config_.keyAt(indices[0]);
322 int32_t stream_id = stream_config_.valueAt(indices[0])[0].streamId;
323
324 Result result = Result::UNKNOWN;
325 tv_input_->openStream(device_id, stream_id,
326 [&result](Result res, const native_handle_t*) {
327 result = res;
328 });
329 EXPECT_EQ(Result::OK, result);
330
331 tv_input_->openStream(device_id, stream_id,
332 [&result](Result res, const native_handle_t*) {
333 result = res;
334 });
335 EXPECT_EQ(Result::INVALID_STATE, result);
336 }
337
338 /*
339 * CloseStreamBeforeOpenTest:
340 * Calls closeStream() without calling openStream() for a stream (if any)
341 * Checks the returned result
342 * The result should be Result::INVALID_STATE
343 */
TEST_F(TvInputHidlTest,CloseStreamBeforeOpenTest)344 TEST_F(TvInputHidlTest, CloseStreamBeforeOpenTest) {
345 std::unique_lock<std::mutex> lock(mutex_);
346 updateAllStreamConfigurations();
347 std::vector<size_t> indices = getConfigIndices();
348 if (indices.empty()) {
349 return;
350 }
351 int32_t device_id = stream_config_.keyAt(indices[0]);
352 int32_t stream_id = stream_config_.valueAt(indices[0])[0].streamId;
353 EXPECT_EQ(Result::INVALID_STATE, tv_input_->closeStream(device_id, stream_id));
354 }
355
main(int argc,char ** argv)356 int main(int argc, char **argv) {
357 ::testing::AddGlobalTestEnvironment(new TvInputHidlEnvironment);
358 ::testing::InitGoogleTest(&argc, argv);
359 int status = RUN_ALL_TESTS();
360 ALOGI("Test result = %d", status);
361 return status;
362 }
363
364