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" 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.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::Void; 39 using ::android::hardware::broadcastradio::V1_0::BandConfig; 40 using ::android::hardware::broadcastradio::V1_0::Class; 41 using ::android::hardware::broadcastradio::V1_0::Direction; 42 using ::android::hardware::broadcastradio::V1_0::IBroadcastRadio; 43 using ::android::hardware::broadcastradio::V1_0::MetaData; 44 using ::android::hardware::broadcastradio::V1_0::Properties; 45 using ::android::hardware::broadcastradio::V1_1::IBroadcastRadioFactory; 46 using ::android::hardware::broadcastradio::V1_1::ITuner; 47 using ::android::hardware::broadcastradio::V1_1::ITunerCallback; 48 using ::android::hardware::broadcastradio::V1_1::ProgramInfo; 49 using ::android::hardware::broadcastradio::V1_1::Result; 50 using ::android::hardware::broadcastradio::V1_1::ProgramListResult; 51 52 53 // The main test class for Broadcast Radio HIDL HAL. 54 55 class BroadcastRadioHidlTest : public ::testing::VtsHalHidlTargetTestBase { 56 protected: 57 virtual void SetUp() override { 58 auto factory = ::testing::VtsHalHidlTargetTestBase::getService<IBroadcastRadioFactory>(); 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()); 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 virtual Return<void> backgroundScanComplete(ProgramListResult result __unused) { 133 return Void(); 134 } 135 136 virtual Return<void> programListChanged() { 137 return Void(); 138 } 139 140 MyCallback(BroadcastRadioHidlTest *parentTest) : mParentTest(parentTest) {} 141 142 private: 143 // BroadcastRadioHidlTest instance to which callbacks will be notified. 144 BroadcastRadioHidlTest *mParentTest; 145 }; 146 147 148 /** 149 * Method called by MyCallback when a callback with no status or boolean value is received 150 */ 151 void onCallback() { 152 Mutex::Autolock _l(mLock); 153 onCallback_l(); 154 } 155 156 /** 157 * Method called by MyCallback when hardwareFailure() callback is received 158 */ 159 void onHwFailureCallback() { 160 Mutex::Autolock _l(mLock); 161 mHwFailure = true; 162 onCallback_l(); 163 } 164 165 /** 166 * Method called by MyCallback when a callback with status is received 167 */ 168 void onResultCallback(Result result) { 169 Mutex::Autolock _l(mLock); 170 mResultCallbackData = result; 171 onCallback_l(); 172 } 173 174 /** 175 * Method called by MyCallback when a boolean indication is received 176 */ 177 void onBoolCallback(bool result) { 178 Mutex::Autolock _l(mLock); 179 mBoolCallbackData = result; 180 onCallback_l(); 181 } 182 183 184 BroadcastRadioHidlTest() : 185 mCallbackCalled(false), mBoolCallbackData(false), 186 mResultCallbackData(Result::OK), mHwFailure(false) {} 187 188 void onCallback_l() { 189 if (!mCallbackCalled) { 190 mCallbackCalled = true; 191 mCallbackCond.broadcast(); 192 } 193 } 194 195 196 bool waitForCallback(nsecs_t reltime = 0) { 197 Mutex::Autolock _l(mLock); 198 nsecs_t endTime = systemTime() + reltime; 199 while (!mCallbackCalled) { 200 if (reltime == 0) { 201 mCallbackCond.wait(mLock); 202 } else { 203 nsecs_t now = systemTime(); 204 if (now > endTime) { 205 return false; 206 } 207 mCallbackCond.waitRelative(mLock, endTime - now); 208 } 209 } 210 return true; 211 } 212 213 bool getProperties(); 214 bool openTuner(); 215 bool checkAntenna(); 216 217 static const nsecs_t kConfigCallbacktimeoutNs = seconds_to_nanoseconds(10); 218 static const nsecs_t kTuneCallbacktimeoutNs = seconds_to_nanoseconds(30); 219 220 sp<IBroadcastRadio> mRadio; 221 Properties mHalProperties; 222 sp<ITuner> mTuner; 223 sp<MyCallback> mTunerCallback; 224 Mutex mLock; 225 Condition mCallbackCond; 226 bool mCallbackCalled; 227 bool mBoolCallbackData; 228 Result mResultCallbackData; 229 bool mHwFailure; 230 }; 231 232 // A class for test environment setup (kept since this file is a template). 233 class BroadcastRadioHidlEnvironment : public ::testing::Environment { 234 public: 235 virtual void SetUp() {} 236 virtual void TearDown() {} 237 }; 238 239 bool BroadcastRadioHidlTest::getProperties() 240 { 241 if (mHalProperties.bands.size() == 0) { 242 Result halResult = Result::NOT_INITIALIZED; 243 Return<void> hidlReturn = 244 mRadio->getProperties([&](Result result, const Properties& properties) { 245 halResult = result; 246 if (result == Result::OK) { 247 mHalProperties = properties; 248 } 249 }); 250 251 EXPECT_TRUE(hidlReturn.isOk()); 252 EXPECT_EQ(Result::OK, halResult); 253 EXPECT_EQ(Class::AM_FM, mHalProperties.classId); 254 EXPECT_GT(mHalProperties.numTuners, 0u); 255 EXPECT_GT(mHalProperties.bands.size(), 0u); 256 } 257 return mHalProperties.bands.size() > 0; 258 } 259 260 bool BroadcastRadioHidlTest::openTuner() 261 { 262 if (!getProperties()) { 263 return false; 264 } 265 if (mTuner.get() == nullptr) { 266 Result halResult = Result::NOT_INITIALIZED; 267 auto hidlReturn = mRadio->openTuner(mHalProperties.bands[0], true, mTunerCallback, 268 [&](Result result, const sp<V1_0::ITuner>& tuner) { 269 halResult = result; 270 if (result == Result::OK) { 271 mTuner = ITuner::castFrom(tuner); 272 } 273 }); 274 EXPECT_TRUE(hidlReturn.isOk()); 275 EXPECT_EQ(Result::OK, halResult); 276 EXPECT_TRUE(waitForCallback(kConfigCallbacktimeoutNs)); 277 } 278 EXPECT_NE(nullptr, mTuner.get()); 279 return nullptr != mTuner.get(); 280 } 281 282 bool BroadcastRadioHidlTest::checkAntenna() 283 { 284 BandConfig halConfig; 285 Result halResult = Result::NOT_INITIALIZED; 286 Return<void> hidlReturn = 287 mTuner->getConfiguration([&](Result result, const BandConfig& config) { 288 halResult = result; 289 if (result == Result::OK) { 290 halConfig = config; 291 } 292 }); 293 294 return ((halResult == Result::OK) && (halConfig.antennaConnected == true)); 295 } 296 297 298 /** 299 * Test IBroadcastRadio::getProperties() method 300 * 301 * Verifies that: 302 * - the HAL implements the method 303 * - the method returns 0 (no error) 304 * - the implementation class is AM_FM 305 * - the implementation supports at least one tuner 306 * - the implementation supports at one band 307 */ 308 TEST_F(BroadcastRadioHidlTest, GetProperties) { 309 EXPECT_TRUE(getProperties()); 310 } 311 312 /** 313 * Test IBroadcastRadio::openTuner() method 314 * 315 * Verifies that: 316 * - the HAL implements the method 317 * - the method returns 0 (no error) and a valid ITuner interface 318 */ 319 TEST_F(BroadcastRadioHidlTest, OpenTuner) { 320 EXPECT_TRUE(openTuner()); 321 } 322 323 /** 324 * Test ITuner::setConfiguration() and getConfiguration methods 325 * 326 * Verifies that: 327 * - the HAL implements both methods 328 * - the methods return 0 (no error) 329 * - the configuration callback is received within kConfigCallbacktimeoutNs ns 330 * - the configuration read back from HAl has the same class Id 331 */ 332 TEST_F(BroadcastRadioHidlTest, SetAndGetConfiguration) { 333 ASSERT_TRUE(openTuner()); 334 // test setConfiguration 335 mCallbackCalled = false; 336 Return<Result> hidlResult = mTuner->setConfiguration(mHalProperties.bands[0]); 337 EXPECT_TRUE(hidlResult.isOk()); 338 EXPECT_EQ(Result::OK, hidlResult); 339 EXPECT_TRUE(waitForCallback(kConfigCallbacktimeoutNs)); 340 EXPECT_EQ(Result::OK, mResultCallbackData); 341 342 // test getConfiguration 343 BandConfig halConfig; 344 Result halResult; 345 Return<void> hidlReturn = 346 mTuner->getConfiguration([&](Result result, const BandConfig& config) { 347 halResult = result; 348 if (result == Result::OK) { 349 halConfig = config; 350 } 351 }); 352 EXPECT_TRUE(hidlReturn.isOk()); 353 EXPECT_EQ(Result::OK, halResult); 354 EXPECT_EQ(mHalProperties.bands[0].type, halConfig.type); 355 } 356 357 /** 358 * Test ITuner::scan 359 * 360 * Verifies that: 361 * - the HAL implements the method 362 * - the method returns 0 (no error) 363 * - the tuned callback is received within kTuneCallbacktimeoutNs ns 364 */ 365 TEST_F(BroadcastRadioHidlTest, Scan) { 366 ASSERT_TRUE(openTuner()); 367 ASSERT_TRUE(checkAntenna()); 368 // test scan UP 369 mCallbackCalled = false; 370 Return<Result> hidlResult = mTuner->scan(Direction::UP, true); 371 EXPECT_TRUE(hidlResult.isOk()); 372 EXPECT_EQ(Result::OK, hidlResult); 373 EXPECT_TRUE(waitForCallback(kTuneCallbacktimeoutNs)); 374 375 // test scan DOWN 376 mCallbackCalled = false; 377 hidlResult = mTuner->scan(Direction::DOWN, true); 378 EXPECT_TRUE(hidlResult.isOk()); 379 EXPECT_EQ(Result::OK, hidlResult); 380 EXPECT_TRUE(waitForCallback(kTuneCallbacktimeoutNs)); 381 } 382 383 /** 384 * Test ITuner::step 385 * 386 * Verifies that: 387 * - the HAL implements the method 388 * - the method returns 0 (no error) 389 * - the tuned callback is received within kTuneCallbacktimeoutNs ns 390 */ 391 TEST_F(BroadcastRadioHidlTest, Step) { 392 ASSERT_TRUE(openTuner()); 393 ASSERT_TRUE(checkAntenna()); 394 // test step UP 395 mCallbackCalled = false; 396 Return<Result> hidlResult = mTuner->step(Direction::UP, true); 397 EXPECT_TRUE(hidlResult.isOk()); 398 EXPECT_EQ(Result::OK, hidlResult); 399 EXPECT_TRUE(waitForCallback(kTuneCallbacktimeoutNs)); 400 401 // test step DOWN 402 mCallbackCalled = false; 403 hidlResult = mTuner->step(Direction::DOWN, true); 404 EXPECT_TRUE(hidlResult.isOk()); 405 EXPECT_EQ(Result::OK, hidlResult); 406 EXPECT_TRUE(waitForCallback(kTuneCallbacktimeoutNs)); 407 } 408 409 /** 410 * Test ITuner::tune, getProgramInformation and cancel methods 411 * 412 * Verifies that: 413 * - the HAL implements the methods 414 * - the methods return 0 (no error) 415 * - the tuned callback is received within kTuneCallbacktimeoutNs ns after tune() 416 */ 417 TEST_F(BroadcastRadioHidlTest, TuneAndGetProgramInformationAndCancel) { 418 ASSERT_TRUE(openTuner()); 419 ASSERT_TRUE(checkAntenna()); 420 421 // test tune 422 ASSERT_GT(mHalProperties.bands[0].spacings.size(), 0u); 423 ASSERT_GT(mHalProperties.bands[0].upperLimit, mHalProperties.bands[0].lowerLimit); 424 425 // test scan UP 426 uint32_t lowerLimit = mHalProperties.bands[0].lowerLimit; 427 uint32_t upperLimit = mHalProperties.bands[0].upperLimit; 428 uint32_t spacing = mHalProperties.bands[0].spacings[0]; 429 430 uint32_t channel = 431 lowerLimit + (((upperLimit - lowerLimit) / 2 + spacing - 1) / spacing) * spacing; 432 mCallbackCalled = false; 433 mResultCallbackData = Result::NOT_INITIALIZED; 434 Return<Result> hidlResult = mTuner->tune(channel, 0); 435 EXPECT_TRUE(hidlResult.isOk()); 436 EXPECT_EQ(Result::OK, hidlResult); 437 EXPECT_TRUE(waitForCallback(kTuneCallbacktimeoutNs)); 438 439 // test getProgramInformation 440 ProgramInfo halInfo; 441 Result halResult = Result::NOT_INITIALIZED; 442 Return<void> hidlReturn = mTuner->getProgramInformation_1_1( 443 [&](Result result, const ProgramInfo& info) { 444 halResult = result; 445 if (result == Result::OK) { 446 halInfo = info; 447 } 448 }); 449 EXPECT_TRUE(hidlReturn.isOk()); 450 EXPECT_EQ(Result::OK, halResult); 451 auto &halInfo_1_1 = halInfo.base; 452 if (mResultCallbackData == Result::OK) { 453 EXPECT_TRUE(halInfo_1_1.tuned); 454 EXPECT_LE(halInfo_1_1.channel, upperLimit); 455 EXPECT_GE(halInfo_1_1.channel, lowerLimit); 456 } else { 457 EXPECT_EQ(false, halInfo_1_1.tuned); 458 } 459 460 // test cancel 461 mTuner->tune(lowerLimit, 0); 462 hidlResult = mTuner->cancel(); 463 EXPECT_TRUE(hidlResult.isOk()); 464 EXPECT_EQ(Result::OK, hidlResult); 465 } 466 467 468 int main(int argc, char** argv) { 469 ::testing::AddGlobalTestEnvironment(new BroadcastRadioHidlEnvironment); 470 ::testing::InitGoogleTest(&argc, argv); 471 int status = RUN_ALL_TESTS(); 472 ALOGI("Test result = %d", status); 473 return status; 474 } 475