1 /* 2 * Copyright (C) 2016 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" 18 #include <VtsHalHidlTargetTestBase.h> 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.0/IBroadcastRadioFactory.h> 26 #include <android/hardware/broadcastradio/1.0/IBroadcastRadio.h> 27 #include <android/hardware/broadcastradio/1.0/ITuner.h> 28 #include <android/hardware/broadcastradio/1.0/ITunerCallback.h> 29 #include <android/hardware/broadcastradio/1.0/types.h> 30 31 32 using ::android::sp; 33 using ::android::Mutex; 34 using ::android::Condition; 35 using ::android::hardware::Return; 36 using ::android::hardware::Void; 37 using ::android::hardware::broadcastradio::V1_0::IBroadcastRadioFactory; 38 using ::android::hardware::broadcastradio::V1_0::IBroadcastRadio; 39 using ::android::hardware::broadcastradio::V1_0::ITuner; 40 using ::android::hardware::broadcastradio::V1_0::ITunerCallback; 41 using ::android::hardware::broadcastradio::V1_0::Result; 42 using ::android::hardware::broadcastradio::V1_0::Class; 43 using ::android::hardware::broadcastradio::V1_0::Properties; 44 using ::android::hardware::broadcastradio::V1_0::Band; 45 using ::android::hardware::broadcastradio::V1_0::BandConfig; 46 using ::android::hardware::broadcastradio::V1_0::Direction; 47 using ::android::hardware::broadcastradio::V1_0::ProgramInfo; 48 using ::android::hardware::broadcastradio::V1_0::MetaData; 49 50 51 #define RETURN_IF_SKIPPED \ 52 if (skipped) { \ 53 std::cout << "[ SKIPPED ] This device class is not supported. " << std::endl; \ 54 return; \ 55 } 56 57 // The main test class for Broadcast Radio HIDL HAL. 58 59 class BroadcastRadioHidlTest : public ::testing::VtsHalHidlTargetTestBase, 60 public ::testing::WithParamInterface<Class> { 61 protected: 62 virtual void SetUp() override { 63 ASSERT_EQ(nullptr, mRadio.get()); 64 65 radioClass = GetParam(); 66 skipped = false; 67 68 sp<IBroadcastRadioFactory> factory = 69 ::testing::VtsHalHidlTargetTestBase::getService<IBroadcastRadioFactory>(); 70 ASSERT_NE(nullptr, factory.get()); 71 72 Result connectResult; 73 factory->connectModule(radioClass, [&](Result ret, const sp<IBroadcastRadio>& radio) { 74 connectResult = ret; 75 mRadio = radio; 76 onCallback_l(); 77 }); 78 EXPECT_EQ(true, waitForCallback(kConnectCallbacktimeoutNs)); 79 mCallbackCalled = false; 80 81 if (connectResult == Result::INVALID_ARGUMENTS) { 82 skipped = true; 83 return; 84 } 85 ASSERT_EQ(connectResult, Result::OK); 86 87 mTunerCallback = new MyCallback(this); 88 ASSERT_NE(nullptr, mRadio.get()); 89 ASSERT_NE(nullptr, mTunerCallback.get()); 90 } 91 92 virtual void TearDown() override { 93 mTuner.clear(); 94 mRadio.clear(); 95 } 96 97 class MyCallback : public ITunerCallback { 98 public: 99 100 // ITunerCallback methods (see doc in ITunerCallback.hal) 101 virtual Return<void> hardwareFailure() { 102 ALOGI("%s", __FUNCTION__); 103 mParentTest->onHwFailureCallback(); 104 return Void(); 105 } 106 107 virtual Return<void> configChange(Result result, const BandConfig& config) { 108 ALOGI("%s result %d", __FUNCTION__, result); 109 mParentTest->onConfigChangeCallback(result, config); 110 return Void(); 111 } 112 113 virtual Return<void> tuneComplete(Result result, const ProgramInfo& info) { 114 ALOGI("%s result %d", __FUNCTION__, result); 115 mParentTest->onTuneCompleteCallback(result, info); 116 return Void(); 117 } 118 119 virtual Return<void> afSwitch(const ProgramInfo& info __unused) { 120 return Void(); 121 } 122 123 virtual Return<void> antennaStateChange(bool connected) { 124 ALOGI("%s connected %d", __FUNCTION__, connected); 125 return Void(); 126 } 127 128 virtual Return<void> trafficAnnouncement(bool active) { 129 ALOGI("%s active %d", __FUNCTION__, active); 130 return Void(); 131 } 132 133 virtual Return<void> emergencyAnnouncement(bool active) { 134 ALOGI("%s active %d", __FUNCTION__, active); 135 return Void(); 136 } 137 138 virtual Return<void> newMetadata(uint32_t channel __unused, uint32_t subChannel __unused, 139 const ::android::hardware::hidl_vec<MetaData>& metadata __unused) { 140 ALOGI("%s", __FUNCTION__); 141 return Void(); 142 } 143 144 MyCallback(BroadcastRadioHidlTest *parentTest) : mParentTest(parentTest) {} 145 146 private: 147 // BroadcastRadioHidlTest instance to which callbacks will be notified. 148 BroadcastRadioHidlTest *mParentTest; 149 }; 150 151 152 /** 153 * Method called by MyCallback when a callback with no status or boolean value is received 154 */ 155 void onCallback() { 156 Mutex::Autolock _l(mLock); 157 onCallback_l(); 158 } 159 160 /** 161 * Method called by MyCallback when hardwareFailure() callback is received 162 */ 163 void onHwFailureCallback() { 164 Mutex::Autolock _l(mLock); 165 mHwFailure = true; 166 onCallback_l(); 167 } 168 169 /** 170 * Method called by MyCallback when configChange() callback is received. 171 */ 172 void onConfigChangeCallback(Result result, const BandConfig& config) { 173 Mutex::Autolock _l(mLock); 174 mResultCallbackData = result; 175 mBandConfigCallbackData = config; 176 onCallback_l(); 177 } 178 179 /** 180 * Method called by MyCallback when tuneComplete() callback is received. 181 */ 182 void onTuneCompleteCallback(Result result, const ProgramInfo& info) { 183 Mutex::Autolock _l(mLock); 184 mResultCallbackData = result; 185 mProgramInfoCallbackData = info; 186 onCallback_l(); 187 } 188 189 /** 190 * Method called by MyCallback when a boolean indication is received 191 */ 192 void onBoolCallback(bool result) { 193 Mutex::Autolock _l(mLock); 194 mBoolCallbackData = result; 195 onCallback_l(); 196 } 197 198 199 BroadcastRadioHidlTest() 200 : mCallbackCalled(false), mBoolCallbackData(false), mResultCallbackData(Result::OK), 201 mHwFailure(false) {} 202 203 void onCallback_l() { 204 if (!mCallbackCalled) { 205 mCallbackCalled = true; 206 mCallbackCond.broadcast(); 207 } 208 } 209 210 211 bool waitForCallback(nsecs_t reltime = 0) { 212 Mutex::Autolock _l(mLock); 213 nsecs_t endTime = systemTime() + reltime; 214 while (!mCallbackCalled) { 215 if (reltime == 0) { 216 mCallbackCond.wait(mLock); 217 } else { 218 nsecs_t now = systemTime(); 219 if (now > endTime) { 220 return false; 221 } 222 mCallbackCond.waitRelative(mLock, endTime - now); 223 } 224 } 225 return true; 226 } 227 228 bool getProperties(); 229 bool openTuner(); 230 bool checkAntenna(); 231 232 static const nsecs_t kConnectCallbacktimeoutNs = seconds_to_nanoseconds(1); 233 static const nsecs_t kConfigCallbacktimeoutNs = seconds_to_nanoseconds(10); 234 static const nsecs_t kTuneCallbacktimeoutNs = seconds_to_nanoseconds(30); 235 236 Class radioClass; 237 bool skipped; 238 sp<IBroadcastRadio> mRadio; 239 Properties mHalProperties; 240 sp<ITuner> mTuner; 241 sp<MyCallback> mTunerCallback; 242 Mutex mLock; 243 Condition mCallbackCond; 244 bool mCallbackCalled; 245 bool mBoolCallbackData; 246 Result mResultCallbackData; 247 ProgramInfo mProgramInfoCallbackData; 248 BandConfig mBandConfigCallbackData; 249 bool mHwFailure; 250 }; 251 252 namespace android { 253 namespace hardware { 254 namespace broadcastradio { 255 namespace V1_0 { 256 257 /** 258 * Compares two BandConfig objects for testing purposes. 259 */ 260 static bool operator==(const BandConfig& l, const BandConfig& r) { 261 if (l.type != r.type) return false; 262 if (l.antennaConnected != r.antennaConnected) return false; 263 if (l.lowerLimit != r.lowerLimit) return false; 264 if (l.upperLimit != r.upperLimit) return false; 265 if (l.spacings != r.spacings) return false; 266 if (l.type == Band::AM || l.type == Band::AM_HD) { 267 return l.ext.am == r.ext.am; 268 } else if (l.type == Band::FM || l.type == Band::FM_HD) { 269 return l.ext.fm == r.ext.fm; 270 } else { 271 // unsupported type 272 return false; 273 } 274 } 275 276 } // V1_0 277 } // broadcastradio 278 } // hardware 279 } // android 280 281 bool BroadcastRadioHidlTest::getProperties() 282 { 283 if (mHalProperties.bands.size() == 0) { 284 Result halResult = Result::NOT_INITIALIZED; 285 Return<void> hidlReturn = 286 mRadio->getProperties([&](Result result, const Properties& properties) { 287 halResult = result; 288 if (result == Result::OK) { 289 mHalProperties = properties; 290 } 291 }); 292 293 EXPECT_TRUE(hidlReturn.isOk()); 294 EXPECT_EQ(Result::OK, halResult); 295 EXPECT_EQ(Class::AM_FM, mHalProperties.classId); 296 EXPECT_GT(mHalProperties.numTuners, 0u); 297 EXPECT_GT(mHalProperties.bands.size(), 0u); 298 } 299 return mHalProperties.bands.size() > 0; 300 } 301 302 bool BroadcastRadioHidlTest::openTuner() 303 { 304 if (!getProperties()) { 305 return false; 306 } 307 if (mTuner.get() == nullptr) { 308 Result halResult = Result::NOT_INITIALIZED; 309 Return<void> hidlReturn = 310 mRadio->openTuner(mHalProperties.bands[0], true, mTunerCallback, 311 [&](Result result, const sp<ITuner>& tuner) { 312 halResult = result; 313 if (result == Result::OK) { 314 mTuner = tuner; 315 } 316 }); 317 EXPECT_TRUE(hidlReturn.isOk()); 318 EXPECT_EQ(Result::OK, halResult); 319 EXPECT_EQ(true, waitForCallback(kConfigCallbacktimeoutNs)); 320 } 321 EXPECT_NE(nullptr, mTuner.get()); 322 return nullptr != mTuner.get(); 323 } 324 325 bool BroadcastRadioHidlTest::checkAntenna() 326 { 327 BandConfig halConfig; 328 Result halResult = Result::NOT_INITIALIZED; 329 Return<void> hidlReturn = 330 mTuner->getConfiguration([&](Result result, const BandConfig& config) { 331 halResult = result; 332 if (result == Result::OK) { 333 halConfig = config; 334 } 335 }); 336 337 return ((halResult == Result::OK) && (halConfig.antennaConnected == true)); 338 } 339 340 341 /** 342 * Test IBroadcastRadio::getProperties() method 343 * 344 * Verifies that: 345 * - the HAL implements the method 346 * - the method returns 0 (no error) 347 * - the implementation class is AM_FM 348 * - the implementation supports at least one tuner 349 * - the implementation supports at one band 350 */ 351 TEST_P(BroadcastRadioHidlTest, GetProperties) { 352 RETURN_IF_SKIPPED; 353 EXPECT_EQ(true, getProperties()); 354 } 355 356 /** 357 * Test IBroadcastRadio::openTuner() method 358 * 359 * Verifies that: 360 * - the HAL implements the method 361 * - the method returns 0 (no error) and a valid ITuner interface 362 */ 363 TEST_P(BroadcastRadioHidlTest, OpenTuner) { 364 RETURN_IF_SKIPPED; 365 EXPECT_EQ(true, openTuner()); 366 } 367 368 /** 369 * Test IBroadcastRadio::openTuner() after ITuner disposal. 370 * 371 * Verifies that: 372 * - ITuner destruction gets propagated through HAL 373 * - the openTuner method works well when called for the second time 374 */ 375 TEST_P(BroadcastRadioHidlTest, ReopenTuner) { 376 RETURN_IF_SKIPPED; 377 EXPECT_TRUE(openTuner()); 378 mTuner.clear(); 379 EXPECT_TRUE(openTuner()); 380 } 381 382 /** 383 * Test IBroadcastRadio::openTuner() method called twice. 384 * 385 * Verifies that: 386 * - the openTuner method fails when called for the second time without deleting previous 387 * ITuner instance 388 */ 389 TEST_P(BroadcastRadioHidlTest, OpenTunerTwice) { 390 RETURN_IF_SKIPPED; 391 EXPECT_TRUE(openTuner()); 392 393 Result halResult = Result::NOT_INITIALIZED; 394 Return<void> hidlReturn = 395 mRadio->openTuner(mHalProperties.bands[0], true, mTunerCallback, 396 [&](Result result, const sp<ITuner>&) { 397 halResult = result; 398 }); 399 EXPECT_TRUE(hidlReturn.isOk()); 400 EXPECT_EQ(Result::INVALID_STATE, halResult); 401 EXPECT_TRUE(waitForCallback(kConfigCallbacktimeoutNs)); 402 } 403 404 /** 405 * Test ITuner::setConfiguration() and getConfiguration methods 406 * 407 * Verifies that: 408 * - the HAL implements both methods 409 * - the methods return 0 (no error) 410 * - the configuration callback is received within kConfigCallbacktimeoutNs ns 411 * - the configuration read back from HAl has the same class Id 412 */ 413 TEST_P(BroadcastRadioHidlTest, SetAndGetConfiguration) { 414 RETURN_IF_SKIPPED; 415 ASSERT_EQ(true, openTuner()); 416 // test setConfiguration 417 mCallbackCalled = false; 418 Return<Result> hidlResult = mTuner->setConfiguration(mHalProperties.bands[1]); 419 EXPECT_TRUE(hidlResult.isOk()); 420 EXPECT_EQ(Result::OK, hidlResult); 421 EXPECT_EQ(true, waitForCallback(kConfigCallbacktimeoutNs)); 422 EXPECT_EQ(Result::OK, mResultCallbackData); 423 EXPECT_EQ(mHalProperties.bands[1], mBandConfigCallbackData); 424 425 // test getConfiguration 426 BandConfig halConfig; 427 Result halResult; 428 Return<void> hidlReturn = 429 mTuner->getConfiguration([&](Result result, const BandConfig& config) { 430 halResult = result; 431 if (result == Result::OK) { 432 halConfig = config; 433 } 434 }); 435 EXPECT_TRUE(hidlReturn.isOk()); 436 EXPECT_EQ(Result::OK, halResult); 437 EXPECT_EQ(mHalProperties.bands[1], halConfig); 438 } 439 440 /** 441 * Test ITuner::setConfiguration() with invalid arguments. 442 * 443 * Verifies that: 444 * - the methods returns INVALID_ARGUMENTS on invalid arguments 445 * - the method recovers and succeeds after passing correct arguments 446 */ 447 TEST_P(BroadcastRadioHidlTest, SetConfigurationFails) { 448 RETURN_IF_SKIPPED; 449 ASSERT_EQ(true, openTuner()); 450 451 // Let's define a config that's bad for sure. 452 BandConfig badConfig = {}; 453 badConfig.type = Band::FM; 454 badConfig.lowerLimit = 0xFFFFFFFF; 455 badConfig.upperLimit = 0; 456 badConfig.spacings = (std::vector<uint32_t>){ 0 }; 457 458 // Test setConfiguration failing on bad data. 459 mCallbackCalled = false; 460 auto setResult = mTuner->setConfiguration(badConfig); 461 EXPECT_TRUE(setResult.isOk()); 462 EXPECT_EQ(Result::INVALID_ARGUMENTS, setResult); 463 464 // Test setConfiguration recovering after passing good data. 465 mCallbackCalled = false; 466 setResult = mTuner->setConfiguration(mHalProperties.bands[0]); 467 EXPECT_TRUE(setResult.isOk()); 468 EXPECT_EQ(Result::OK, setResult); 469 EXPECT_EQ(true, waitForCallback(kConfigCallbacktimeoutNs)); 470 EXPECT_EQ(Result::OK, mResultCallbackData); 471 } 472 473 /** 474 * Test ITuner::scan 475 * 476 * Verifies that: 477 * - the HAL implements the method 478 * - the method returns 0 (no error) 479 * - the tuned callback is received within kTuneCallbacktimeoutNs ns 480 * - skipping sub-channel or not does not fail the call 481 */ 482 TEST_P(BroadcastRadioHidlTest, Scan) { 483 RETURN_IF_SKIPPED; 484 ASSERT_EQ(true, openTuner()); 485 ASSERT_TRUE(checkAntenna()); 486 // test scan UP 487 mCallbackCalled = false; 488 Return<Result> hidlResult = mTuner->scan(Direction::UP, true); 489 EXPECT_TRUE(hidlResult.isOk()); 490 EXPECT_EQ(Result::OK, hidlResult); 491 EXPECT_EQ(true, waitForCallback(kTuneCallbacktimeoutNs)); 492 493 // test scan DOWN 494 mCallbackCalled = false; 495 hidlResult = mTuner->scan(Direction::DOWN, false); 496 EXPECT_TRUE(hidlResult.isOk()); 497 EXPECT_EQ(Result::OK, hidlResult); 498 EXPECT_EQ(true, waitForCallback(kTuneCallbacktimeoutNs)); 499 } 500 501 /** 502 * Test ITuner::step 503 * 504 * Verifies that: 505 * - the HAL implements the method 506 * - the method returns 0 (no error) 507 * - the tuned callback is received within kTuneCallbacktimeoutNs ns 508 * - skipping sub-channel or not does not fail the call 509 */ 510 TEST_P(BroadcastRadioHidlTest, Step) { 511 RETURN_IF_SKIPPED; 512 ASSERT_EQ(true, openTuner()); 513 ASSERT_TRUE(checkAntenna()); 514 // test step UP 515 mCallbackCalled = false; 516 Return<Result> hidlResult = mTuner->step(Direction::UP, false); 517 EXPECT_TRUE(hidlResult.isOk()); 518 EXPECT_EQ(Result::OK, hidlResult); 519 EXPECT_EQ(true, waitForCallback(kTuneCallbacktimeoutNs)); 520 521 // test step DOWN 522 mCallbackCalled = false; 523 hidlResult = mTuner->step(Direction::DOWN, true); 524 EXPECT_TRUE(hidlResult.isOk()); 525 EXPECT_EQ(Result::OK, hidlResult); 526 EXPECT_EQ(true, waitForCallback(kTuneCallbacktimeoutNs)); 527 } 528 529 /** 530 * Test ITuner::tune, getProgramInformation and cancel methods 531 * 532 * Verifies that: 533 * - the HAL implements the methods 534 * - the methods return 0 (no error) 535 * - the tuned callback is received within kTuneCallbacktimeoutNs ns after tune() 536 */ 537 TEST_P(BroadcastRadioHidlTest, TuneAndGetProgramInformationAndCancel) { 538 RETURN_IF_SKIPPED; 539 ASSERT_EQ(true, openTuner()); 540 ASSERT_TRUE(checkAntenna()); 541 542 // test tune 543 ASSERT_GT(mHalProperties.bands[0].spacings.size(), 0u); 544 ASSERT_GT(mHalProperties.bands[0].upperLimit, mHalProperties.bands[0].lowerLimit); 545 546 // test scan UP 547 uint32_t lowerLimit = mHalProperties.bands[0].lowerLimit; 548 uint32_t upperLimit = mHalProperties.bands[0].upperLimit; 549 uint32_t spacing = mHalProperties.bands[0].spacings[0]; 550 551 uint32_t channel = 552 lowerLimit + (((upperLimit - lowerLimit) / 2 + spacing - 1) / spacing) * spacing; 553 mCallbackCalled = false; 554 mResultCallbackData = Result::NOT_INITIALIZED; 555 Return<Result> hidlResult = mTuner->tune(channel, 0); 556 EXPECT_TRUE(hidlResult.isOk()); 557 EXPECT_EQ(Result::OK, hidlResult); 558 EXPECT_EQ(true, waitForCallback(kTuneCallbacktimeoutNs)); 559 EXPECT_EQ(channel, mProgramInfoCallbackData.channel); 560 561 // test getProgramInformation 562 ProgramInfo halInfo; 563 Result halResult = Result::NOT_INITIALIZED; 564 Return<void> hidlReturn = mTuner->getProgramInformation( 565 [&](Result result, const ProgramInfo& info) { 566 halResult = result; 567 if (result == Result::OK) { 568 halInfo = info; 569 } 570 }); 571 EXPECT_TRUE(hidlReturn.isOk()); 572 EXPECT_EQ(Result::OK, halResult); 573 if (mResultCallbackData == Result::OK) { 574 EXPECT_EQ(true, halInfo.tuned); 575 EXPECT_LE(halInfo.channel, upperLimit); 576 EXPECT_GE(halInfo.channel, lowerLimit); 577 } else { 578 EXPECT_EQ(false, halInfo.tuned); 579 } 580 581 // test cancel 582 mTuner->tune(lowerLimit, 0); 583 hidlResult = mTuner->cancel(); 584 EXPECT_TRUE(hidlResult.isOk()); 585 EXPECT_EQ(Result::OK, hidlResult); 586 } 587 588 /** 589 * Test ITuner::tune failing when channel out of the range is provided. 590 * 591 * Verifies that: 592 * - the method returns INVALID_ARGUMENTS when applicable 593 * - the method recovers and succeeds after passing correct arguments 594 */ 595 TEST_P(BroadcastRadioHidlTest, TuneFailsOutOfBounds) { 596 RETURN_IF_SKIPPED; 597 ASSERT_TRUE(openTuner()); 598 ASSERT_TRUE(checkAntenna()); 599 600 // get current channel bounds 601 BandConfig halConfig; 602 Result halResult; 603 auto configResult = mTuner->getConfiguration([&](Result result, const BandConfig& config) { 604 halResult = result; 605 halConfig = config; 606 }); 607 ASSERT_TRUE(configResult.isOk()); 608 ASSERT_EQ(Result::OK, halResult); 609 610 // try to tune slightly above the limit and expect to fail 611 auto badChannel = halConfig.upperLimit + halConfig.spacings[0]; 612 auto tuneResult = mTuner->tune(badChannel, 0); 613 EXPECT_TRUE(tuneResult.isOk()); 614 EXPECT_EQ(Result::INVALID_ARGUMENTS, tuneResult); 615 EXPECT_TRUE(waitForCallback(kTuneCallbacktimeoutNs)); 616 617 // tuning exactly at the limit should succeed 618 auto goodChannel = halConfig.upperLimit; 619 tuneResult = mTuner->tune(goodChannel, 0); 620 EXPECT_TRUE(tuneResult.isOk()); 621 EXPECT_EQ(Result::OK, tuneResult); 622 EXPECT_TRUE(waitForCallback(kTuneCallbacktimeoutNs)); 623 } 624 625 INSTANTIATE_TEST_CASE_P( 626 BroadcastRadioHidlTestCases, 627 BroadcastRadioHidlTest, 628 ::testing::Values(Class::AM_FM, Class::SAT, Class::DT)); 629 630 int main(int argc, char** argv) { 631 ::testing::InitGoogleTest(&argc, argv); 632 int status = RUN_ALL_TESTS(); 633 ALOGI("Test result = %d", status); 634 return status; 635 } 636