Home | History | Annotate | Download | only in functional
      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