Tomasz Wasilczyk | 213170b | 2017-02-07 17:38:21 -0800 | [diff] [blame] | 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 "BroadcastRadioHidlHalTest" |
Yuexi Ma | 50d7e27 | 2017-02-28 01:46:51 -0800 | [diff] [blame] | 18 | #include <VtsHalHidlTargetBaseTest.h> |
Tomasz Wasilczyk | 213170b | 2017-02-07 17:38:21 -0800 | [diff] [blame] | 19 | #include <android-base/logging.h> |
| 20 | #include <cutils/native_handle.h> |
| 21 | #include <cutils/properties.h> |
| 22 | #include <hidl/HidlTransportSupport.h> |
| 23 | #include <utils/threads.h> |
| 24 | |
| 25 | #include <android/hardware/broadcastradio/1.1/IBroadcastRadioFactory.h> |
| 26 | #include <android/hardware/broadcastradio/1.0/IBroadcastRadio.h> |
| 27 | #include <android/hardware/broadcastradio/1.1/ITuner.h> |
| 28 | #include <android/hardware/broadcastradio/1.1/ITunerCallback.h> |
| 29 | #include <android/hardware/broadcastradio/1.1/types.h> |
| 30 | |
| 31 | |
| 32 | namespace V1_0 = ::android::hardware::broadcastradio::V1_0; |
| 33 | |
| 34 | using ::android::sp; |
| 35 | using ::android::Mutex; |
| 36 | using ::android::Condition; |
| 37 | using ::android::hardware::Return; |
| 38 | using ::android::hardware::Status; |
| 39 | using ::android::hardware::Void; |
| 40 | using ::android::hardware::broadcastradio::V1_0::BandConfig; |
| 41 | using ::android::hardware::broadcastradio::V1_0::Class; |
| 42 | using ::android::hardware::broadcastradio::V1_0::Direction; |
| 43 | using ::android::hardware::broadcastradio::V1_0::IBroadcastRadio; |
| 44 | using ::android::hardware::broadcastradio::V1_0::MetaData; |
| 45 | using ::android::hardware::broadcastradio::V1_0::Properties; |
| 46 | using ::android::hardware::broadcastradio::V1_1::IBroadcastRadioFactory; |
| 47 | using ::android::hardware::broadcastradio::V1_1::ITuner; |
| 48 | using ::android::hardware::broadcastradio::V1_1::ITunerCallback; |
| 49 | using ::android::hardware::broadcastradio::V1_1::ProgramInfo; |
| 50 | using ::android::hardware::broadcastradio::V1_1::Result; |
| 51 | |
| 52 | |
| 53 | // The main test class for Broadcast Radio HIDL HAL. |
| 54 | |
Yuexi Ma | 50d7e27 | 2017-02-28 01:46:51 -0800 | [diff] [blame] | 55 | class BroadcastRadioHidlTest : public ::testing::VtsHalHidlTargetBaseTest { |
Tomasz Wasilczyk | 213170b | 2017-02-07 17:38:21 -0800 | [diff] [blame] | 56 | protected: |
| 57 | virtual void SetUp() override { |
Yuexi Ma | 50d7e27 | 2017-02-28 01:46:51 -0800 | [diff] [blame] | 58 | auto factory = ::testing::VtsHalHidlTargetBaseTest::getService<IBroadcastRadioFactory>(); |
Tomasz Wasilczyk | 213170b | 2017-02-07 17:38:21 -0800 | [diff] [blame] | 59 | if (factory != 0) { |
| 60 | factory->connectModule(Class::AM_FM, |
| 61 | [&](Result retval, const ::android::sp<IBroadcastRadio>& result) { |
| 62 | if (retval == Result::OK) { |
| 63 | mRadio = IBroadcastRadio::castFrom(result); |
| 64 | } |
| 65 | }); |
| 66 | } |
| 67 | mTunerCallback = new MyCallback(this); |
| 68 | ASSERT_NE(nullptr, mRadio.get()); |
Tomasz Wasilczyk | 213170b | 2017-02-07 17:38:21 -0800 | [diff] [blame] | 69 | ASSERT_NE(nullptr, mTunerCallback.get()); |
| 70 | } |
| 71 | |
| 72 | virtual void TearDown() override { |
| 73 | mTuner.clear(); |
| 74 | mRadio.clear(); |
| 75 | } |
| 76 | |
| 77 | class MyCallback : public ITunerCallback { |
| 78 | public: |
| 79 | |
| 80 | // ITunerCallback methods (see doc in ITunerCallback.hal) |
| 81 | virtual Return<void> hardwareFailure() { |
| 82 | ALOGI("%s", __FUNCTION__); |
| 83 | mParentTest->onHwFailureCallback(); |
| 84 | return Void(); |
| 85 | } |
| 86 | |
| 87 | virtual Return<void> configChange(Result result, const BandConfig& config __unused) { |
| 88 | ALOGI("%s result %d", __FUNCTION__, result); |
| 89 | mParentTest->onResultCallback(result); |
| 90 | return Void(); |
| 91 | } |
| 92 | |
| 93 | virtual Return<void> tuneComplete(Result result __unused, const V1_0::ProgramInfo& info __unused) { |
| 94 | return Void(); |
| 95 | } |
| 96 | |
| 97 | virtual Return<void> tuneComplete_1_1(Result result, const ProgramInfo& info __unused) { |
| 98 | ALOGI("%s result %d", __FUNCTION__, result); |
| 99 | mParentTest->onResultCallback(result); |
| 100 | return Void(); |
| 101 | } |
| 102 | |
| 103 | virtual Return<void> afSwitch(const V1_0::ProgramInfo& info __unused) { |
| 104 | return Void(); |
| 105 | } |
| 106 | |
| 107 | virtual Return<void> afSwitch_1_1(const ProgramInfo& info __unused) { |
| 108 | return Void(); |
| 109 | } |
| 110 | |
| 111 | virtual Return<void> antennaStateChange(bool connected) { |
| 112 | ALOGI("%s connected %d", __FUNCTION__, connected); |
| 113 | return Void(); |
| 114 | } |
| 115 | |
| 116 | virtual Return<void> trafficAnnouncement(bool active) { |
| 117 | ALOGI("%s active %d", __FUNCTION__, active); |
| 118 | return Void(); |
| 119 | } |
| 120 | |
| 121 | virtual Return<void> emergencyAnnouncement(bool active) { |
| 122 | ALOGI("%s active %d", __FUNCTION__, active); |
| 123 | return Void(); |
| 124 | } |
| 125 | |
| 126 | virtual Return<void> newMetadata(uint32_t channel __unused, uint32_t subChannel __unused, |
| 127 | const ::android::hardware::hidl_vec<MetaData>& metadata __unused) { |
| 128 | ALOGI("%s", __FUNCTION__); |
| 129 | return Void(); |
| 130 | } |
| 131 | |
| 132 | MyCallback(BroadcastRadioHidlTest *parentTest) : mParentTest(parentTest) {} |
| 133 | |
| 134 | private: |
| 135 | // BroadcastRadioHidlTest instance to which callbacks will be notified. |
| 136 | BroadcastRadioHidlTest *mParentTest; |
| 137 | }; |
| 138 | |
| 139 | |
| 140 | /** |
| 141 | * Method called by MyCallback when a callback with no status or boolean value is received |
| 142 | */ |
| 143 | void onCallback() { |
| 144 | Mutex::Autolock _l(mLock); |
| 145 | onCallback_l(); |
| 146 | } |
| 147 | |
| 148 | /** |
| 149 | * Method called by MyCallback when hardwareFailure() callback is received |
| 150 | */ |
| 151 | void onHwFailureCallback() { |
| 152 | Mutex::Autolock _l(mLock); |
| 153 | mHwFailure = true; |
| 154 | onCallback_l(); |
| 155 | } |
| 156 | |
| 157 | /** |
| 158 | * Method called by MyCallback when a callback with status is received |
| 159 | */ |
| 160 | void onResultCallback(Result result) { |
| 161 | Mutex::Autolock _l(mLock); |
| 162 | mResultCallbackData = result; |
| 163 | onCallback_l(); |
| 164 | } |
| 165 | |
| 166 | /** |
| 167 | * Method called by MyCallback when a boolean indication is received |
| 168 | */ |
| 169 | void onBoolCallback(bool result) { |
| 170 | Mutex::Autolock _l(mLock); |
| 171 | mBoolCallbackData = result; |
| 172 | onCallback_l(); |
| 173 | } |
| 174 | |
| 175 | |
| 176 | BroadcastRadioHidlTest() : |
| 177 | mCallbackCalled(false), mBoolCallbackData(false), |
| 178 | mResultCallbackData(Result::OK), mHwFailure(false) {} |
| 179 | |
| 180 | void onCallback_l() { |
| 181 | if (!mCallbackCalled) { |
| 182 | mCallbackCalled = true; |
| 183 | mCallbackCond.broadcast(); |
| 184 | } |
| 185 | } |
| 186 | |
| 187 | |
| 188 | bool waitForCallback(nsecs_t reltime = 0) { |
| 189 | Mutex::Autolock _l(mLock); |
| 190 | nsecs_t endTime = systemTime() + reltime; |
| 191 | while (!mCallbackCalled) { |
| 192 | if (reltime == 0) { |
| 193 | mCallbackCond.wait(mLock); |
| 194 | } else { |
| 195 | nsecs_t now = systemTime(); |
| 196 | if (now > endTime) { |
| 197 | return false; |
| 198 | } |
| 199 | mCallbackCond.waitRelative(mLock, endTime - now); |
| 200 | } |
| 201 | } |
| 202 | return true; |
| 203 | } |
| 204 | |
| 205 | bool getProperties(); |
| 206 | bool openTuner(); |
| 207 | bool checkAntenna(); |
| 208 | |
| 209 | static const nsecs_t kConfigCallbacktimeoutNs = seconds_to_nanoseconds(10); |
| 210 | static const nsecs_t kTuneCallbacktimeoutNs = seconds_to_nanoseconds(30); |
| 211 | |
| 212 | sp<IBroadcastRadio> mRadio; |
| 213 | Properties mHalProperties; |
| 214 | sp<ITuner> mTuner; |
| 215 | sp<MyCallback> mTunerCallback; |
| 216 | Mutex mLock; |
| 217 | Condition mCallbackCond; |
| 218 | bool mCallbackCalled; |
| 219 | bool mBoolCallbackData; |
| 220 | Result mResultCallbackData; |
| 221 | bool mHwFailure; |
| 222 | }; |
| 223 | |
| 224 | // A class for test environment setup (kept since this file is a template). |
| 225 | class BroadcastRadioHidlEnvironment : public ::testing::Environment { |
| 226 | public: |
| 227 | virtual void SetUp() {} |
| 228 | virtual void TearDown() {} |
| 229 | }; |
| 230 | |
| 231 | bool BroadcastRadioHidlTest::getProperties() |
| 232 | { |
| 233 | if (mHalProperties.bands.size() == 0) { |
| 234 | Result halResult = Result::NOT_INITIALIZED; |
| 235 | Return<void> hidlReturn = |
| 236 | mRadio->getProperties([&](Result result, const Properties& properties) { |
| 237 | halResult = result; |
| 238 | if (result == Result::OK) { |
| 239 | mHalProperties = properties; |
| 240 | } |
| 241 | }); |
| 242 | |
| 243 | EXPECT_TRUE(hidlReturn.isOk()); |
| 244 | EXPECT_EQ(Result::OK, halResult); |
| 245 | EXPECT_EQ(Class::AM_FM, mHalProperties.classId); |
| 246 | EXPECT_GT(mHalProperties.numTuners, 0u); |
| 247 | EXPECT_GT(mHalProperties.bands.size(), 0u); |
| 248 | } |
| 249 | return mHalProperties.bands.size() > 0; |
| 250 | } |
| 251 | |
| 252 | bool BroadcastRadioHidlTest::openTuner() |
| 253 | { |
| 254 | if (!getProperties()) { |
| 255 | return false; |
| 256 | } |
| 257 | if (mTuner.get() == nullptr) { |
| 258 | Result halResult = Result::NOT_INITIALIZED; |
| 259 | auto hidlReturn = mRadio->openTuner(mHalProperties.bands[0], true, mTunerCallback, |
| 260 | [&](Result result, const sp<V1_0::ITuner>& tuner) { |
| 261 | halResult = result; |
| 262 | if (result == Result::OK) { |
| 263 | mTuner = ITuner::castFrom(tuner); |
| 264 | } |
| 265 | }); |
| 266 | EXPECT_TRUE(hidlReturn.isOk()); |
| 267 | EXPECT_EQ(Result::OK, halResult); |
| 268 | EXPECT_TRUE(waitForCallback(kConfigCallbacktimeoutNs)); |
| 269 | } |
| 270 | EXPECT_NE(nullptr, mTuner.get()); |
| 271 | return nullptr != mTuner.get(); |
| 272 | } |
| 273 | |
| 274 | bool BroadcastRadioHidlTest::checkAntenna() |
| 275 | { |
| 276 | BandConfig halConfig; |
| 277 | Result halResult = Result::NOT_INITIALIZED; |
| 278 | Return<void> hidlReturn = |
| 279 | mTuner->getConfiguration([&](Result result, const BandConfig& config) { |
| 280 | halResult = result; |
| 281 | if (result == Result::OK) { |
| 282 | halConfig = config; |
| 283 | } |
| 284 | }); |
| 285 | |
| 286 | return ((halResult == Result::OK) && (halConfig.antennaConnected == true)); |
| 287 | } |
| 288 | |
| 289 | |
| 290 | /** |
| 291 | * Test IBroadcastRadio::getProperties() method |
| 292 | * |
| 293 | * Verifies that: |
| 294 | * - the HAL implements the method |
| 295 | * - the method returns 0 (no error) |
| 296 | * - the implementation class is AM_FM |
| 297 | * - the implementation supports at least one tuner |
| 298 | * - the implementation supports at one band |
| 299 | */ |
| 300 | TEST_F(BroadcastRadioHidlTest, GetProperties) { |
| 301 | EXPECT_TRUE(getProperties()); |
| 302 | } |
| 303 | |
| 304 | /** |
| 305 | * Test IBroadcastRadio::openTuner() method |
| 306 | * |
| 307 | * Verifies that: |
| 308 | * - the HAL implements the method |
| 309 | * - the method returns 0 (no error) and a valid ITuner interface |
| 310 | */ |
| 311 | TEST_F(BroadcastRadioHidlTest, OpenTuner) { |
| 312 | EXPECT_TRUE(openTuner()); |
| 313 | } |
| 314 | |
| 315 | /** |
| 316 | * Test ITuner::setConfiguration() and getConfiguration methods |
| 317 | * |
| 318 | * Verifies that: |
| 319 | * - the HAL implements both methods |
| 320 | * - the methods return 0 (no error) |
| 321 | * - the configuration callback is received within kConfigCallbacktimeoutNs ns |
| 322 | * - the configuration read back from HAl has the same class Id |
| 323 | */ |
| 324 | TEST_F(BroadcastRadioHidlTest, SetAndGetConfiguration) { |
| 325 | ASSERT_TRUE(openTuner()); |
| 326 | // test setConfiguration |
| 327 | mCallbackCalled = false; |
| 328 | Return<Result> hidlResult = mTuner->setConfiguration(mHalProperties.bands[0]); |
| 329 | EXPECT_TRUE(hidlResult.isOk()); |
| 330 | EXPECT_EQ(Result::OK, hidlResult); |
| 331 | EXPECT_TRUE(waitForCallback(kConfigCallbacktimeoutNs)); |
| 332 | EXPECT_EQ(Result::OK, mResultCallbackData); |
| 333 | |
| 334 | // test getConfiguration |
| 335 | BandConfig halConfig; |
| 336 | Result halResult; |
| 337 | Return<void> hidlReturn = |
| 338 | mTuner->getConfiguration([&](Result result, const BandConfig& config) { |
| 339 | halResult = result; |
| 340 | if (result == Result::OK) { |
| 341 | halConfig = config; |
| 342 | } |
| 343 | }); |
| 344 | EXPECT_TRUE(hidlReturn.isOk()); |
| 345 | EXPECT_EQ(Result::OK, halResult); |
| 346 | EXPECT_EQ(mHalProperties.bands[0].type, halConfig.type); |
| 347 | } |
| 348 | |
| 349 | /** |
| 350 | * Test ITuner::scan |
| 351 | * |
| 352 | * Verifies that: |
| 353 | * - the HAL implements the method |
| 354 | * - the method returns 0 (no error) |
| 355 | * - the tuned callback is received within kTuneCallbacktimeoutNs ns |
| 356 | */ |
| 357 | TEST_F(BroadcastRadioHidlTest, Scan) { |
| 358 | ASSERT_TRUE(openTuner()); |
| 359 | ASSERT_TRUE(checkAntenna()); |
| 360 | // test scan UP |
| 361 | mCallbackCalled = false; |
| 362 | Return<Result> hidlResult = mTuner->scan(Direction::UP, true); |
| 363 | EXPECT_TRUE(hidlResult.isOk()); |
| 364 | EXPECT_EQ(Result::OK, hidlResult); |
| 365 | EXPECT_TRUE(waitForCallback(kTuneCallbacktimeoutNs)); |
| 366 | |
| 367 | // test scan DOWN |
| 368 | mCallbackCalled = false; |
| 369 | hidlResult = mTuner->scan(Direction::DOWN, true); |
| 370 | EXPECT_TRUE(hidlResult.isOk()); |
| 371 | EXPECT_EQ(Result::OK, hidlResult); |
| 372 | EXPECT_TRUE(waitForCallback(kTuneCallbacktimeoutNs)); |
| 373 | } |
| 374 | |
| 375 | /** |
| 376 | * Test ITuner::step |
| 377 | * |
| 378 | * Verifies that: |
| 379 | * - the HAL implements the method |
| 380 | * - the method returns 0 (no error) |
| 381 | * - the tuned callback is received within kTuneCallbacktimeoutNs ns |
| 382 | */ |
| 383 | TEST_F(BroadcastRadioHidlTest, Step) { |
| 384 | ASSERT_TRUE(openTuner()); |
| 385 | ASSERT_TRUE(checkAntenna()); |
| 386 | // test step UP |
| 387 | mCallbackCalled = false; |
| 388 | Return<Result> hidlResult = mTuner->step(Direction::UP, true); |
| 389 | EXPECT_TRUE(hidlResult.isOk()); |
| 390 | EXPECT_EQ(Result::OK, hidlResult); |
| 391 | EXPECT_TRUE(waitForCallback(kTuneCallbacktimeoutNs)); |
| 392 | |
| 393 | // test step DOWN |
| 394 | mCallbackCalled = false; |
| 395 | hidlResult = mTuner->step(Direction::DOWN, true); |
| 396 | EXPECT_TRUE(hidlResult.isOk()); |
| 397 | EXPECT_EQ(Result::OK, hidlResult); |
| 398 | EXPECT_TRUE(waitForCallback(kTuneCallbacktimeoutNs)); |
| 399 | } |
| 400 | |
| 401 | /** |
| 402 | * Test ITuner::tune, getProgramInformation and cancel methods |
| 403 | * |
| 404 | * Verifies that: |
| 405 | * - the HAL implements the methods |
| 406 | * - the methods return 0 (no error) |
| 407 | * - the tuned callback is received within kTuneCallbacktimeoutNs ns after tune() |
| 408 | */ |
| 409 | TEST_F(BroadcastRadioHidlTest, TuneAndGetProgramInformationAndCancel) { |
| 410 | ASSERT_TRUE(openTuner()); |
| 411 | ASSERT_TRUE(checkAntenna()); |
| 412 | |
| 413 | // test tune |
| 414 | ASSERT_GT(mHalProperties.bands[0].spacings.size(), 0u); |
| 415 | ASSERT_GT(mHalProperties.bands[0].upperLimit, mHalProperties.bands[0].lowerLimit); |
| 416 | |
| 417 | // test scan UP |
| 418 | uint32_t lowerLimit = mHalProperties.bands[0].lowerLimit; |
| 419 | uint32_t upperLimit = mHalProperties.bands[0].upperLimit; |
| 420 | uint32_t spacing = mHalProperties.bands[0].spacings[0]; |
| 421 | |
| 422 | uint32_t channel = |
| 423 | lowerLimit + (((upperLimit - lowerLimit) / 2 + spacing - 1) / spacing) * spacing; |
| 424 | mCallbackCalled = false; |
| 425 | mResultCallbackData = Result::NOT_INITIALIZED; |
| 426 | Return<Result> hidlResult = mTuner->tune(channel, 0); |
| 427 | EXPECT_TRUE(hidlResult.isOk()); |
| 428 | EXPECT_EQ(Result::OK, hidlResult); |
| 429 | EXPECT_TRUE(waitForCallback(kTuneCallbacktimeoutNs)); |
| 430 | |
| 431 | // test getProgramInformation |
| 432 | ProgramInfo halInfo; |
| 433 | Result halResult = Result::NOT_INITIALIZED; |
| 434 | Return<void> hidlReturn = mTuner->getProgramInformation_1_1( |
| 435 | [&](Result result, const ProgramInfo& info) { |
| 436 | halResult = result; |
| 437 | if (result == Result::OK) { |
| 438 | halInfo = info; |
| 439 | } |
| 440 | }); |
| 441 | EXPECT_TRUE(hidlReturn.isOk()); |
| 442 | EXPECT_EQ(Result::OK, halResult); |
| 443 | auto &halInfo_1_1 = halInfo.base; |
| 444 | if (mResultCallbackData == Result::OK) { |
| 445 | EXPECT_TRUE(halInfo_1_1.tuned); |
| 446 | EXPECT_LE(halInfo_1_1.channel, upperLimit); |
| 447 | EXPECT_GE(halInfo_1_1.channel, lowerLimit); |
| 448 | } else { |
| 449 | EXPECT_EQ(false, halInfo_1_1.tuned); |
| 450 | } |
| 451 | |
| 452 | // test cancel |
| 453 | mTuner->tune(lowerLimit, 0); |
| 454 | hidlResult = mTuner->cancel(); |
| 455 | EXPECT_TRUE(hidlResult.isOk()); |
| 456 | EXPECT_EQ(Result::OK, hidlResult); |
| 457 | } |
| 458 | |
| 459 | |
| 460 | int main(int argc, char** argv) { |
| 461 | ::testing::AddGlobalTestEnvironment(new BroadcastRadioHidlEnvironment); |
| 462 | ::testing::InitGoogleTest(&argc, argv); |
| 463 | int status = RUN_ALL_TESTS(); |
| 464 | ALOGI("Test result = %d", status); |
| 465 | return status; |
| 466 | } |