• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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