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