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: 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 58 virtual void TearDown() override {} 59 60 /* Called when a DEVICE_AVAILABLE event is received. */ 61 void onDeviceAvailable(const TvInputDeviceInfo& deviceInfo) { 62 device_info_.add(deviceInfo.deviceId, deviceInfo); 63 } 64 65 /* Called when a DEVICE_UNAVAILABLE event is received. */ 66 void onDeviceUnavailable(int32_t deviceId) { 67 device_info_.removeItem(deviceId); 68 } 69 70 /* Called when a DEVICE_CONFIGURATIONS_CHANGED event is received. */ 71 Result onStreamConfigurationsChanged(int32_t deviceId) { 72 return updateStreamConfigurations(deviceId); 73 } 74 75 /* Gets and updates the stream configurations for a device. */ 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. */ 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. */ 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 */ 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: 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 */ 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: 193 virtual void SetUp() {} 194 virtual void TearDown() {} 195 196 private: 197 }; 198 199 /* 200 * GetStreamConfigTest: 201 * Calls updateStreamConfigurations() for each existing device 202 * Checks returned results 203 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 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