xref: /aosp_15_r20/hardware/interfaces/broadcastradio/aidl/vts/src/VtsHalBroadcastradioAidlTargetTest.cpp (revision 4d7e907c777eeecc4c5bd7cf640a754fac206ff7)
1 /*
2  * Copyright (C) 2022 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 EGMOCK_VERBOSE 1
18 
19 #include <aidl/android/hardware/broadcastradio/Alert.h>
20 #include <aidl/android/hardware/broadcastradio/BnAnnouncementListener.h>
21 #include <aidl/android/hardware/broadcastradio/BnTunerCallback.h>
22 #include <aidl/android/hardware/broadcastradio/ConfigFlag.h>
23 #include <aidl/android/hardware/broadcastradio/IBroadcastRadio.h>
24 #include <aidl/android/hardware/broadcastradio/ProgramListChunk.h>
25 #include <aidl/android/hardware/broadcastradio/ProgramSelector.h>
26 #include <aidl/android/hardware/broadcastradio/VendorKeyValue.h>
27 #include <android-base/logging.h>
28 #include <android-base/strings.h>
29 #include <android-base/thread_annotations.h>
30 #include <android/binder_manager.h>
31 #include <android/binder_process.h>
32 
33 #include <aidl/Gtest.h>
34 #include <aidl/Vintf.h>
35 #include <broadcastradio-utils-aidl/Utils.h>
36 #include <broadcastradio-utils-aidl/UtilsV2.h>
37 #include <cutils/bitops.h>
38 #include <gmock/gmock.h>
39 #include <gtest/gtest.h>
40 
41 #include <chrono>
42 #include <condition_variable>
43 #include <optional>
44 #include <regex>
45 
46 namespace aidl::android::hardware::broadcastradio::vts {
47 
48 namespace {
49 
50 using ::aidl::android::hardware::broadcastradio::utils::makeIdentifier;
51 using ::aidl::android::hardware::broadcastradio::utils::makeSelectorAmfm;
52 using ::aidl::android::hardware::broadcastradio::utils::makeSelectorDab;
53 using ::aidl::android::hardware::broadcastradio::utils::resultToInt;
54 using ::ndk::ScopedAStatus;
55 using ::ndk::SharedRefBase;
56 using ::std::vector;
57 using ::testing::_;
58 using ::testing::AnyNumber;
59 using ::testing::ByMove;
60 using ::testing::DoAll;
61 using ::testing::Invoke;
62 using ::testing::SaveArg;
63 
64 namespace bcutils = ::aidl::android::hardware::broadcastradio::utils;
65 
66 const ConfigFlag kConfigFlagValues[] = {
67         ConfigFlag::FORCE_MONO,
68         ConfigFlag::FORCE_ANALOG,
69         ConfigFlag::FORCE_DIGITAL,
70         ConfigFlag::RDS_AF,
71         ConfigFlag::RDS_REG,
72         ConfigFlag::DAB_DAB_LINKING,
73         ConfigFlag::DAB_FM_LINKING,
74         ConfigFlag::DAB_DAB_SOFT_LINKING,
75         ConfigFlag::DAB_FM_SOFT_LINKING,
76 };
77 
78 constexpr int32_t kAidlVersion1 = 1;
79 constexpr int32_t kAidlVersion2 = 2;
80 constexpr int32_t kAidlVersion3 = 3;
81 
isValidAmFmFreq(int64_t freq,int aidlVersion)82 bool isValidAmFmFreq(int64_t freq, int aidlVersion) {
83     ProgramIdentifier id = bcutils::makeIdentifier(IdentifierType::AMFM_FREQUENCY_KHZ, freq);
84     if (aidlVersion == kAidlVersion1) {
85         return bcutils::isValid(id);
86     } else if (aidlVersion >= kAidlVersion2) {
87         return bcutils::isValidV2(id);
88     }
89     LOG(ERROR) << "Unknown AIDL version " << aidlVersion;
90     return false;
91 }
92 
validateRange(const AmFmBandRange & range,int aidlVersion)93 void validateRange(const AmFmBandRange& range, int aidlVersion) {
94     EXPECT_TRUE(isValidAmFmFreq(range.lowerBound, aidlVersion));
95     EXPECT_TRUE(isValidAmFmFreq(range.upperBound, aidlVersion));
96     EXPECT_LT(range.lowerBound, range.upperBound);
97     EXPECT_GT(range.spacing, 0u);
98     EXPECT_EQ((range.upperBound - range.lowerBound) % range.spacing, 0u);
99 }
100 
supportsFM(const AmFmRegionConfig & config)101 bool supportsFM(const AmFmRegionConfig& config) {
102     for (const auto& range : config.ranges) {
103         if (bcutils::getBand(range.lowerBound) == bcutils::FrequencyBand::FM) {
104             return true;
105         }
106     }
107     return false;
108 }
109 
validateMetadata(const ProgramInfo & info,int32_t aidlVersion)110 void validateMetadata(const ProgramInfo& info, int32_t aidlVersion) {
111     for (const auto& metadataItem : info.metadata) {
112         bool validMetadata = false;
113         if (aidlVersion == kAidlVersion1) {
114             validMetadata = bcutils::isValidMetadata(metadataItem);
115         } else {
116             validMetadata = bcutils::isValidMetadataV2(metadataItem);
117         }
118         EXPECT_TRUE(validMetadata) << "Invalid metadata " << metadataItem.toString().c_str();
119     }
120 }
121 
validateAlert(const ProgramInfo & info,int32_t aidlVersion)122 void validateAlert(const ProgramInfo& info, int32_t aidlVersion) {
123     if (aidlVersion < kAidlVersion3 || !info.emergencyAlert.has_value()) {
124         return;
125     }
126     Alert alert = info.emergencyAlert.value();
127     ASSERT_FALSE(alert.infoArray.empty());
128     for (const auto& alertInfo : alert.infoArray) {
129         ASSERT_FALSE(alertInfo.categoryArray.empty());
130         if (alertInfo.areas.empty()) {
131             continue;
132         }
133         for (const auto& area : alertInfo.areas) {
134             if (area.polygons.empty()) {
135                 continue;
136             }
137             for (const auto& polygon : area.polygons) {
138                 ASSERT_GE(polygon.coordinates.size(), 4);
139                 EXPECT_EQ(polygon.coordinates.front(), polygon.coordinates.back());
140             }
141         }
142     }
143 }
144 
145 }  // namespace
146 
147 class CallbackFlag final {
148   public:
CallbackFlag(int timeoutMs)149     CallbackFlag(int timeoutMs) { mTimeoutMs = timeoutMs; }
150     /**
151      * Notify that the callback is called.
152      */
notify()153     void notify() {
154         std::unique_lock<std::mutex> lock(mMutex);
155         mCalled = true;
156         lock.unlock();
157         mCv.notify_all();
158     };
159 
160     /**
161      * Wait for the timeout passed into the constructor.
162      */
wait()163     bool wait() {
164         std::unique_lock<std::mutex> lock(mMutex);
165         return mCv.wait_for(lock, std::chrono::milliseconds(mTimeoutMs),
166                             [this] { return mCalled; });
167     };
168 
169     /**
170      * Reset the callback to not called.
171      */
reset()172     void reset() {
173         std::unique_lock<std::mutex> lock(mMutex);
174         mCalled = false;
175     }
176 
177   private:
178     std::mutex mMutex;
179     bool mCalled GUARDED_BY(mMutex) = false;
180     std::condition_variable mCv;
181     int mTimeoutMs;
182 };
183 
184 class TunerCallbackImpl final : public BnTunerCallback {
185   public:
186     explicit TunerCallbackImpl(int32_t aidlVersion);
187     ScopedAStatus onTuneFailed(Result result, const ProgramSelector& selector) override;
188     ScopedAStatus onCurrentProgramInfoChanged(const ProgramInfo& info) override;
189     ScopedAStatus onProgramListUpdated(const ProgramListChunk& chunk) override;
190     ScopedAStatus onParametersUpdated(const vector<VendorKeyValue>& parameters) override;
191     ScopedAStatus onAntennaStateChange(bool connected) override;
192     ScopedAStatus onConfigFlagUpdated(ConfigFlag in_flag, bool in_value) override;
193 
194     bool waitOnCurrentProgramInfoChangedCallback();
195     bool waitProgramReady();
196     void reset();
197 
198     bool getAntennaConnectionState();
199     ProgramInfo getCurrentProgramInfo();
200     bcutils::ProgramInfoSet getProgramList();
201 
202   private:
203     std::mutex mLock;
204     int32_t mCallbackAidlVersion;
205     bool mAntennaConnectionState GUARDED_BY(mLock);
206     ProgramInfo mCurrentProgramInfo GUARDED_BY(mLock);
207     bcutils::ProgramInfoSet mProgramList GUARDED_BY(mLock);
208     CallbackFlag mOnCurrentProgramInfoChangedFlag = CallbackFlag(IBroadcastRadio::TUNER_TIMEOUT_MS);
209     CallbackFlag mOnProgramListReadyFlag = CallbackFlag(IBroadcastRadio::LIST_COMPLETE_TIMEOUT_MS);
210 };
211 
212 struct AnnouncementListenerMock : public BnAnnouncementListener {
213     MOCK_METHOD1(onListUpdated, ScopedAStatus(const vector<Announcement>&));
214 };
215 
216 class BroadcastRadioHalTest : public testing::TestWithParam<std::string> {
217   protected:
218     void SetUp() override;
219     void TearDown() override;
220 
221     bool getAmFmRegionConfig(bool full, AmFmRegionConfig* config);
222     std::optional<bcutils::ProgramInfoSet> getProgramList();
223     std::optional<bcutils::ProgramInfoSet> getProgramList(const ProgramFilter& filter);
224 
225     std::shared_ptr<IBroadcastRadio> mModule;
226     Properties mProperties;
227     std::shared_ptr<TunerCallbackImpl> mCallback;
228     int32_t mAidlVersion;
229 };
230 
231 MATCHER_P(InfoHasId, id,
232           std::string(negation ? "does not contain" : "contains") + " " + id.toString()) {
233     vector<int64_t> ids = bcutils::getAllIds(arg.selector, id.type);
234     return ids.end() != find(ids.begin(), ids.end(), id.value);
235 }
236 
TunerCallbackImpl(int32_t aidlVersion)237 TunerCallbackImpl::TunerCallbackImpl(int32_t aidlVersion) {
238     mCallbackAidlVersion = aidlVersion;
239     mAntennaConnectionState = true;
240 }
241 
onTuneFailed(Result result,const ProgramSelector & selector)242 ScopedAStatus TunerCallbackImpl::onTuneFailed(Result result, const ProgramSelector& selector) {
243     LOG(DEBUG) << "Tune failed for selector" << selector.toString();
244     EXPECT_TRUE(result == Result::CANCELED);
245     return ndk::ScopedAStatus::ok();
246 }
247 
onCurrentProgramInfoChanged(const ProgramInfo & info)248 ScopedAStatus TunerCallbackImpl::onCurrentProgramInfoChanged(const ProgramInfo& info) {
249     LOG(DEBUG) << "onCurrentProgramInfoChanged called";
250     for (const auto& id : info.selector) {
251         EXPECT_NE(id.type, IdentifierType::INVALID);
252     }
253 
254     IdentifierType logically = info.logicallyTunedTo.type;
255     // This field is required for currently tuned program and should be INVALID
256     // for entries from the program list.
257     EXPECT_TRUE(logically == IdentifierType::AMFM_FREQUENCY_KHZ ||
258                 logically == IdentifierType::RDS_PI ||
259                 logically == IdentifierType::HD_STATION_ID_EXT ||
260                 logically == IdentifierType::DAB_SID_EXT ||
261                 logically == IdentifierType::DRMO_SERVICE_ID ||
262                 logically == IdentifierType::SXM_SERVICE_ID ||
263                 (logically >= IdentifierType::VENDOR_START &&
264                  logically <= IdentifierType::VENDOR_END) ||
265                 logically > IdentifierType::SXM_CHANNEL);
266 
267     IdentifierType physically = info.physicallyTunedTo.type;
268     // ditto (see "logically" above)
269     EXPECT_TRUE(physically == IdentifierType::AMFM_FREQUENCY_KHZ ||
270                 physically == IdentifierType::DAB_FREQUENCY_KHZ ||
271                 physically == IdentifierType::DRMO_FREQUENCY_KHZ ||
272                 physically == IdentifierType::SXM_CHANNEL ||
273                 (physically >= IdentifierType::VENDOR_START &&
274                  physically <= IdentifierType::VENDOR_END) ||
275                 physically > IdentifierType::SXM_CHANNEL);
276 
277     if (logically == IdentifierType::AMFM_FREQUENCY_KHZ) {
278         std::optional<std::string> ps;
279         if (mCallbackAidlVersion == kAidlVersion1) {
280             ps = bcutils::getMetadataString(info, Metadata::rdsPs);
281         } else {
282             ps = bcutils::getMetadataStringV2(info, Metadata::rdsPs);
283         }
284         if (ps.has_value()) {
285             EXPECT_NE(::android::base::Trim(*ps), "")
286                     << "Don't use empty RDS_PS as an indicator of missing RSD PS data.";
287         }
288     }
289 
290     validateMetadata(info, mCallbackAidlVersion);
291 
292     validateAlert(info, mCallbackAidlVersion);
293 
294     {
295         std::lock_guard<std::mutex> lk(mLock);
296         mCurrentProgramInfo = info;
297     }
298 
299     mOnCurrentProgramInfoChangedFlag.notify();
300     return ndk::ScopedAStatus::ok();
301 }
302 
onProgramListUpdated(const ProgramListChunk & chunk)303 ScopedAStatus TunerCallbackImpl::onProgramListUpdated(const ProgramListChunk& chunk) {
304     LOG(DEBUG) << "onProgramListUpdated called";
305     {
306         std::lock_guard<std::mutex> lk(mLock);
307         updateProgramList(chunk, &mProgramList);
308     }
309 
310     if (chunk.complete) {
311         mOnProgramListReadyFlag.notify();
312     }
313 
314     return ndk::ScopedAStatus::ok();
315 }
316 
onParametersUpdated(const vector<VendorKeyValue> & parameters)317 ScopedAStatus TunerCallbackImpl::onParametersUpdated(
318         [[maybe_unused]] const vector<VendorKeyValue>& parameters) {
319     return ndk::ScopedAStatus::ok();
320 }
321 
onAntennaStateChange(bool connected)322 ScopedAStatus TunerCallbackImpl::onAntennaStateChange(bool connected) {
323     if (!connected) {
324         std::lock_guard<std::mutex> lk(mLock);
325         mAntennaConnectionState = false;
326     }
327     return ndk::ScopedAStatus::ok();
328 }
329 
onConfigFlagUpdated(ConfigFlag in_flag,bool in_value)330 ScopedAStatus TunerCallbackImpl::onConfigFlagUpdated([[maybe_unused]] ConfigFlag in_flag,
331                                                      [[maybe_unused]] bool in_value) {
332     return ndk::ScopedAStatus::ok();
333 }
334 
waitOnCurrentProgramInfoChangedCallback()335 bool TunerCallbackImpl::waitOnCurrentProgramInfoChangedCallback() {
336     return mOnCurrentProgramInfoChangedFlag.wait();
337 }
338 
waitProgramReady()339 bool TunerCallbackImpl::waitProgramReady() {
340     return mOnProgramListReadyFlag.wait();
341 }
342 
reset()343 void TunerCallbackImpl::reset() {
344     mOnCurrentProgramInfoChangedFlag.reset();
345     mOnProgramListReadyFlag.reset();
346 }
347 
getAntennaConnectionState()348 bool TunerCallbackImpl::getAntennaConnectionState() {
349     std::lock_guard<std::mutex> lk(mLock);
350     return mAntennaConnectionState;
351 }
352 
getCurrentProgramInfo()353 ProgramInfo TunerCallbackImpl::getCurrentProgramInfo() {
354     std::lock_guard<std::mutex> lk(mLock);
355     return mCurrentProgramInfo;
356 }
357 
getProgramList()358 bcutils::ProgramInfoSet TunerCallbackImpl::getProgramList() {
359     std::lock_guard<std::mutex> lk(mLock);
360     return mProgramList;
361 }
362 
SetUp()363 void BroadcastRadioHalTest::SetUp() {
364     EXPECT_EQ(mModule.get(), nullptr) << "Module is already open";
365 
366     // lookup AIDL service (radio module)
367     AIBinder* binder = AServiceManager_waitForService(GetParam().c_str());
368     ASSERT_NE(binder, nullptr);
369     mModule = IBroadcastRadio::fromBinder(ndk::SpAIBinder(binder));
370     ASSERT_NE(mModule, nullptr) << "Couldn't find broadcast radio HAL implementation";
371 
372     // get module properties
373     auto propResult = mModule->getProperties(&mProperties);
374 
375     ASSERT_TRUE(propResult.isOk());
376     EXPECT_FALSE(mProperties.maker.empty());
377     EXPECT_FALSE(mProperties.product.empty());
378     EXPECT_GT(mProperties.supportedIdentifierTypes.size(), 0u);
379 
380     // get AIDL HAL version
381     ASSERT_TRUE(mModule->getInterfaceVersion(&mAidlVersion).isOk());
382     EXPECT_GE(mAidlVersion, kAidlVersion1);
383     EXPECT_LE(mAidlVersion, kAidlVersion3);
384 
385     // set callback
386     mCallback = SharedRefBase::make<TunerCallbackImpl>(mAidlVersion);
387     EXPECT_TRUE(mModule->setTunerCallback(mCallback).isOk());
388 }
389 
TearDown()390 void BroadcastRadioHalTest::TearDown() {
391     if (mModule) {
392         ASSERT_TRUE(mModule->unsetTunerCallback().isOk());
393     }
394     if (mCallback) {
395         // we expect the antenna is connected through the whole test
396         EXPECT_TRUE(mCallback->getAntennaConnectionState());
397         mCallback = nullptr;
398     }
399 }
400 
getAmFmRegionConfig(bool full,AmFmRegionConfig * config)401 bool BroadcastRadioHalTest::getAmFmRegionConfig(bool full, AmFmRegionConfig* config) {
402     auto halResult = mModule->getAmFmRegionConfig(full, config);
403 
404     if (halResult.getServiceSpecificError() == resultToInt(Result::NOT_SUPPORTED)) {
405         return false;
406     }
407 
408     EXPECT_TRUE(halResult.isOk());
409     return halResult.isOk();
410 }
411 
getProgramList()412 std::optional<bcutils::ProgramInfoSet> BroadcastRadioHalTest::getProgramList() {
413     ProgramFilter emptyFilter = {};
414     return getProgramList(emptyFilter);
415 }
416 
getProgramList(const ProgramFilter & filter)417 std::optional<bcutils::ProgramInfoSet> BroadcastRadioHalTest::getProgramList(
418         const ProgramFilter& filter) {
419     mCallback->reset();
420 
421     auto startResult = mModule->startProgramListUpdates(filter);
422 
423     if (startResult.getServiceSpecificError() == resultToInt(Result::NOT_SUPPORTED)) {
424         LOG(WARNING) << "Program list not supported";
425         return std::nullopt;
426     }
427     EXPECT_TRUE(startResult.isOk());
428     if (!startResult.isOk()) {
429         return std::nullopt;
430     }
431     EXPECT_TRUE(mCallback->waitProgramReady());
432 
433     auto stopResult = mModule->stopProgramListUpdates();
434 
435     EXPECT_TRUE(stopResult.isOk());
436 
437     return mCallback->getProgramList();
438 }
439 
440 /**
441  * Test setting tuner callback to null.
442  *
443  * Verifies that:
444  *  - Setting to a null tuner callback results with INVALID_ARGUMENTS.
445  */
TEST_P(BroadcastRadioHalTest,TunerCallbackFailsWithNull)446 TEST_P(BroadcastRadioHalTest, TunerCallbackFailsWithNull) {
447     LOG(DEBUG) << "TunerCallbackFailsWithNull Test";
448 
449     auto halResult = mModule->setTunerCallback(nullptr);
450 
451     EXPECT_EQ(halResult.getServiceSpecificError(), resultToInt(Result::INVALID_ARGUMENTS));
452 }
453 
454 /**
455  * Test fetching AM/FM regional configuration.
456  *
457  * Verifies that:
458  *  - AM/FM regional configuration is either set at startup or not supported at all by the hardware;
459  *  - FM Deemphasis and RDS are correctly configured for FM-capable radio;
460  */
TEST_P(BroadcastRadioHalTest,GetAmFmRegionConfig)461 TEST_P(BroadcastRadioHalTest, GetAmFmRegionConfig) {
462     LOG(DEBUG) << "GetAmFmRegionConfig Test";
463 
464     AmFmRegionConfig config;
465 
466     bool supported = getAmFmRegionConfig(/* full= */ false, &config);
467 
468     if (!supported) {
469         GTEST_SKIP() << "AM/FM not supported";
470     }
471 
472     EXPECT_LE(popcountll(static_cast<unsigned long long>(config.fmDeemphasis)), 1);
473     EXPECT_LE(popcountll(static_cast<unsigned long long>(config.fmRds)), 1);
474 
475     if (supportsFM(config)) {
476         EXPECT_EQ(popcountll(static_cast<unsigned long long>(config.fmDeemphasis)), 1);
477     }
478 }
479 
480 /**
481  * Test fetching ranges of AM/FM regional configuration.
482  *
483  * Verifies that:
484  *  - AM/FM regional configuration is either set at startup or not supported at all by the hardware;
485  *  - there is at least one AM/FM band configured;
486  *  - all channel grids (frequency ranges and spacings) are valid;
487  *  - seek spacing is a multiple of the manual spacing value.
488  */
TEST_P(BroadcastRadioHalTest,GetAmFmRegionConfigRanges)489 TEST_P(BroadcastRadioHalTest, GetAmFmRegionConfigRanges) {
490     LOG(DEBUG) << "GetAmFmRegionConfigRanges Test";
491 
492     AmFmRegionConfig config;
493 
494     bool supported = getAmFmRegionConfig(/* full= */ false, &config);
495 
496     if (!supported) {
497         GTEST_SKIP() << "AM/FM not supported";
498     }
499 
500     EXPECT_GT(config.ranges.size(), 0u);
501     for (const auto& range : config.ranges) {
502         validateRange(range, mAidlVersion);
503         EXPECT_EQ(range.seekSpacing % range.spacing, 0u);
504         EXPECT_GE(range.seekSpacing, range.spacing);
505     }
506 }
507 
508 /**
509  * Test fetching FM regional capabilities.
510  *
511  * Verifies that:
512  *  - AM/FM regional capabilities are either available or not supported at all by the hardware;
513  *  - there is at least one de-emphasis filter mode supported for FM-capable radio;
514  */
TEST_P(BroadcastRadioHalTest,GetAmFmRegionConfigCapabilitiesForFM)515 TEST_P(BroadcastRadioHalTest, GetAmFmRegionConfigCapabilitiesForFM) {
516     LOG(DEBUG) << "GetAmFmRegionConfigCapabilitiesForFM Test";
517 
518     AmFmRegionConfig config;
519 
520     bool supported = getAmFmRegionConfig(/* full= */ true, &config);
521 
522     if (supported && supportsFM(config)) {
523         EXPECT_GE(popcountll(static_cast<unsigned long long>(config.fmDeemphasis)), 1);
524     } else {
525         GTEST_SKIP() << "FM not supported";
526     }
527 }
528 
529 /**
530  * Test fetching the ranges of AM/FM regional capabilities.
531  *
532  * Verifies that:
533  *  - AM/FM regional capabilities are either available or not supported at all by the hardware;
534  *  - there is at least one AM/FM range supported;
535  *  - all channel grids (frequency ranges and spacings) are valid;
536  *  - seek spacing is not set.
537  */
TEST_P(BroadcastRadioHalTest,GetAmFmRegionConfigCapabilitiesRanges)538 TEST_P(BroadcastRadioHalTest, GetAmFmRegionConfigCapabilitiesRanges) {
539     LOG(DEBUG) << "GetAmFmRegionConfigCapabilitiesRanges Test";
540 
541     AmFmRegionConfig config;
542 
543     bool supported = getAmFmRegionConfig(/* full= */ true, &config);
544 
545     if (!supported) {
546         GTEST_SKIP() << "AM/FM not supported";
547     }
548 
549     EXPECT_GT(config.ranges.size(), 0u);
550 
551     for (const auto& range : config.ranges) {
552         validateRange(range, mAidlVersion);
553         EXPECT_EQ(range.seekSpacing, 0u);
554     }
555 }
556 
557 /**
558  * Test fetching DAB regional configuration.
559  *
560  * Verifies that:
561  *  - DAB regional configuration is either set at startup or not supported at all by the hardware;
562  *  - all channel labels match correct format;
563  *  - all channel frequencies are in correct range.
564  */
TEST_P(BroadcastRadioHalTest,GetDabRegionConfig)565 TEST_P(BroadcastRadioHalTest, GetDabRegionConfig) {
566     LOG(DEBUG) << "GetDabRegionConfig Test";
567     vector<DabTableEntry> config;
568 
569     auto halResult = mModule->getDabRegionConfig(&config);
570 
571     if (halResult.getServiceSpecificError() == resultToInt(Result::NOT_SUPPORTED)) {
572         GTEST_SKIP() << "DAB not supported";
573     }
574     ASSERT_TRUE(halResult.isOk());
575 
576     std::regex re("^[A-Z0-9][A-Z0-9 ]{0,5}[A-Z0-9]$");
577 
578     for (const auto& entry : config) {
579         EXPECT_TRUE(std::regex_match(std::string(entry.label), re));
580 
581         ProgramIdentifier id =
582                 bcutils::makeIdentifier(IdentifierType::DAB_FREQUENCY_KHZ, entry.frequencyKhz);
583         if (mAidlVersion == kAidlVersion1) {
584             EXPECT_TRUE(bcutils::isValid(id));
585         } else if (mAidlVersion == kAidlVersion2) {
586             EXPECT_TRUE(bcutils::isValidV2(id));
587         } else {
588             LOG(ERROR) << "Unknown callback AIDL version " << mAidlVersion;
589         }
590     }
591 }
592 
593 /**
594  * Test tuning without tuner callback set.
595  *
596  * Verifies that:
597  *  - No tuner callback set results in INVALID_STATE, regardless of whether the selector is
598  * supported.
599  */
TEST_P(BroadcastRadioHalTest,TuneFailsWithoutTunerCallback)600 TEST_P(BroadcastRadioHalTest, TuneFailsWithoutTunerCallback) {
601     LOG(DEBUG) << "TuneFailsWithoutTunerCallback Test";
602 
603     mModule->unsetTunerCallback();
604     int64_t freq = 90900;  // 90.9 FM
605     ProgramSelector sel = makeSelectorAmfm(freq);
606 
607     auto result = mModule->tune(sel);
608 
609     EXPECT_EQ(result.getServiceSpecificError(), resultToInt(Result::INVALID_STATE));
610 }
611 
612 /**
613  * Test tuning with selectors that can be not supported.
614  *
615  * Verifies that:
616  *  - if the selector is not supported, an invalid value results with NOT_SUPPORTED, regardless of
617  *    whether it is valid;
618  *  - if it is supported, the test is ignored;
619  */
TEST_P(BroadcastRadioHalTest,TuneFailsWithNotSupported)620 TEST_P(BroadcastRadioHalTest, TuneFailsWithNotSupported) {
621     LOG(DEBUG) << "TuneFailsWithNotSupported Test";
622 
623     vector<ProgramIdentifier> supportTestId = {
624             makeIdentifier(IdentifierType::AMFM_FREQUENCY_KHZ, 0),           // invalid
625             makeIdentifier(IdentifierType::AMFM_FREQUENCY_KHZ, 94900),       // valid
626             makeIdentifier(IdentifierType::RDS_PI, 0x10000),                 // invalid
627             makeIdentifier(IdentifierType::RDS_PI, 0x1001),                  // valid
628             makeIdentifier(IdentifierType::HD_STATION_ID_EXT, 0x100000000),  // invalid
629             makeIdentifier(IdentifierType::HD_STATION_ID_EXT, 0x10000001),   // valid
630             makeIdentifier(IdentifierType::DAB_SID_EXT, 0),                  // invalid
631             makeIdentifier(IdentifierType::DAB_SID_EXT, 0xA00001),           // valid
632             makeIdentifier(IdentifierType::DRMO_SERVICE_ID, 0x100000000),    // invalid
633             makeIdentifier(IdentifierType::DRMO_SERVICE_ID, 0x10000001),     // valid
634             makeIdentifier(IdentifierType::SXM_SERVICE_ID, 0x100000000),     // invalid
635             makeIdentifier(IdentifierType::SXM_SERVICE_ID, 0x10000001),      // valid
636     };
637 
638     auto notSupportedError = resultToInt(Result::NOT_SUPPORTED);
639     for (const auto& id : supportTestId) {
640         ProgramSelector sel{id, {}};
641 
642         if (!bcutils::isSupported(mProperties, sel)) {
643             auto result = mModule->tune(sel);
644 
645             EXPECT_EQ(result.getServiceSpecificError(), notSupportedError);
646         }
647     }
648 }
649 
650 /**
651  * Test tuning with invalid selectors.
652  *
653  * Verifies that:
654  *  - if the selector is not supported, it's ignored;
655  *  - if it is supported, an invalid value results with INVALID_ARGUMENTS;
656  */
TEST_P(BroadcastRadioHalTest,TuneFailsWithInvalid)657 TEST_P(BroadcastRadioHalTest, TuneFailsWithInvalid) {
658     LOG(DEBUG) << "TuneFailsWithInvalid Test";
659 
660     vector<ProgramIdentifier> invalidId = {
661             makeIdentifier(IdentifierType::AMFM_FREQUENCY_KHZ, 0),
662             makeIdentifier(IdentifierType::RDS_PI, 0x10000),
663             makeIdentifier(IdentifierType::HD_STATION_ID_EXT, 0x100000000),
664             makeIdentifier(IdentifierType::DAB_SID_EXT, 0),
665             makeIdentifier(IdentifierType::DRMO_SERVICE_ID, 0x100000000),
666             makeIdentifier(IdentifierType::SXM_SERVICE_ID, 0x100000000),
667     };
668 
669     auto invalidArgumentsError = resultToInt(Result::INVALID_ARGUMENTS);
670     for (const auto& id : invalidId) {
671         ProgramSelector sel{id, {}};
672 
673         if (bcutils::isSupported(mProperties, sel)) {
674             auto result = mModule->tune(sel);
675 
676             EXPECT_EQ(result.getServiceSpecificError(), invalidArgumentsError);
677         }
678     }
679 }
680 
681 /**
682  * Test tuning with empty program selector.
683  *
684  * Verifies that:
685  *  - tune fails with NOT_SUPPORTED when program selector is not initialized.
686  */
TEST_P(BroadcastRadioHalTest,TuneFailsWithEmpty)687 TEST_P(BroadcastRadioHalTest, TuneFailsWithEmpty) {
688     LOG(DEBUG) << "TuneFailsWithEmpty Test";
689 
690     // Program type is 1-based, so 0 will always be invalid.
691     ProgramSelector sel = {};
692 
693     auto result = mModule->tune(sel);
694 
695     ASSERT_EQ(result.getServiceSpecificError(), resultToInt(Result::NOT_SUPPORTED));
696 }
697 
698 /**
699  * Test tuning with FM selector.
700  *
701  * Verifies that:
702  *  - if AM/FM selector is not supported, the method returns NOT_SUPPORTED;
703  *  - if it is supported, the method succeeds;
704  *  - after a successful tune call, onCurrentProgramInfoChanged callback is
705  *    invoked carrying a proper selector;
706  *  - program changes to a program info with the program selector requested.
707  */
TEST_P(BroadcastRadioHalTest,FmTune)708 TEST_P(BroadcastRadioHalTest, FmTune) {
709     LOG(DEBUG) << "FmTune Test";
710 
711     int64_t freq = 90900;  // 90.9 FM
712     ProgramSelector sel = makeSelectorAmfm(freq);
713     // try tuning
714     mCallback->reset();
715     auto result = mModule->tune(sel);
716 
717     // expect a failure if it's not supported
718     if (!bcutils::isSupported(mProperties, sel)) {
719         EXPECT_EQ(result.getServiceSpecificError(), resultToInt(Result::NOT_SUPPORTED));
720         return;
721     }
722 
723     // expect a callback if it succeeds
724     EXPECT_TRUE(result.isOk());
725     EXPECT_TRUE(mCallback->waitOnCurrentProgramInfoChangedCallback());
726     ProgramInfo infoCb = mCallback->getCurrentProgramInfo();
727 
728     LOG(DEBUG) << "Current program info: " << infoCb.toString();
729 
730     // it should tune exactly to what was requested
731     vector<int64_t> freqs = bcutils::getAllIds(infoCb.selector, IdentifierType::AMFM_FREQUENCY_KHZ);
732     EXPECT_NE(freqs.end(), find(freqs.begin(), freqs.end(), freq))
733             << "FM freq " << freq << " kHz is not sent back by callback.";
734 }
735 
736 /**
737  * Test tuning with HD selector.
738  *
739  * Verifies that:
740  *  - if AM/FM HD selector is not supported, the method returns NOT_SUPPORTED;
741  *  - if it is supported, the method succeeds;
742  *  - after a successful tune call, onCurrentProgramInfoChanged callback is
743  *    invoked carrying a proper selector;
744  *  - program changes to a program info with the program selector requested.
745  */
TEST_P(BroadcastRadioHalTest,HdTune)746 TEST_P(BroadcastRadioHalTest, HdTune) {
747     LOG(DEBUG) << "HdTune Test";
748     auto programList = getProgramList();
749     if (!programList) {
750         GTEST_SKIP() << "Empty station list, tune cannot be performed";
751     }
752     ProgramSelector hdSel = {};
753     ProgramIdentifier physicallyTunedToExpected = {};
754     bool hdStationPresent = false;
755     for (auto&& programInfo : *programList) {
756         if (programInfo.selector.primaryId.type != IdentifierType::HD_STATION_ID_EXT) {
757             continue;
758         }
759         hdSel = programInfo.selector;
760         hdStationPresent = true;
761         physicallyTunedToExpected = bcutils::makeIdentifier(IdentifierType::AMFM_FREQUENCY_KHZ,
762                                                             bcutils::getAmFmFrequency(hdSel));
763         break;
764     }
765     if (!hdStationPresent) {
766         GTEST_SKIP() << "No HD stations in the list, tune cannot be performed";
767     }
768 
769     // try tuning
770     auto result = mModule->tune(hdSel);
771 
772     // expect a failure if it's not supported
773     if (!bcutils::isSupported(mProperties, hdSel)) {
774         EXPECT_EQ(result.getServiceSpecificError(), resultToInt(Result::NOT_SUPPORTED));
775         return;
776     }
777     // expect a callback if it succeeds
778     EXPECT_TRUE(result.isOk());
779     EXPECT_TRUE(mCallback->waitOnCurrentProgramInfoChangedCallback());
780     ProgramInfo infoCb = mCallback->getCurrentProgramInfo();
781     LOG(DEBUG) << "Current program info: " << infoCb.toString();
782     // it should tune exactly to what was requested
783     EXPECT_EQ(infoCb.selector.primaryId, hdSel.primaryId);
784     EXPECT_EQ(infoCb.physicallyTunedTo, physicallyTunedToExpected);
785 }
786 
787 /**
788  * Test tuning with DAB selector.
789  *
790  * Verifies that:
791  *  - if DAB selector is not supported, the method returns NOT_SUPPORTED;
792  *  - if it is supported, the method succeeds;
793  *  - after a successful tune call, onCurrentProgramInfoChanged callback is
794  *    invoked carrying a proper selector;
795  *  - program changes to a program info with the program selector requested.
796  */
TEST_P(BroadcastRadioHalTest,DabTune)797 TEST_P(BroadcastRadioHalTest, DabTune) {
798     LOG(DEBUG) << "DabTune Test";
799     vector<DabTableEntry> config;
800 
801     auto halResult = mModule->getDabRegionConfig(&config);
802 
803     if (halResult.getServiceSpecificError() == resultToInt(Result::NOT_SUPPORTED)) {
804         GTEST_SKIP() << "DAB not supported";
805     }
806     ASSERT_TRUE(halResult.isOk());
807     ASSERT_NE(config.size(), 0U);
808 
809     auto programList = getProgramList();
810 
811     if (!programList) {
812         GTEST_SKIP() << "Empty DAB station list, tune cannot be performed";
813     }
814 
815     ProgramSelector sel = {};
816     uint64_t freq = 0;
817     bool dabStationPresent = false;
818     for (auto&& programInfo : *programList) {
819         if (!utils::hasId(programInfo.selector, IdentifierType::DAB_FREQUENCY_KHZ)) {
820             continue;
821         }
822         for (auto&& config_entry : config) {
823             if (config_entry.frequencyKhz ==
824                 utils::getId(programInfo.selector, IdentifierType::DAB_FREQUENCY_KHZ, 0)) {
825                 freq = config_entry.frequencyKhz;
826                 break;
827             }
828         }
829         // Do not trigger a tune request if the programList entry does not contain
830         // a valid DAB frequency.
831         if (freq == 0) {
832             continue;
833         }
834         int64_t dabSidExt = utils::getId(programInfo.selector, IdentifierType::DAB_SID_EXT, 0);
835         int64_t dabEns = utils::getId(programInfo.selector, IdentifierType::DAB_ENSEMBLE, 0);
836         sel = makeSelectorDab(dabSidExt, (int32_t)dabEns, freq);
837         dabStationPresent = true;
838         break;
839     }
840 
841     if (!dabStationPresent) {
842         GTEST_SKIP() << "No DAB stations in the list, tune cannot be performed";
843     }
844 
845     // try tuning
846 
847     auto result = mModule->tune(sel);
848 
849     // expect a failure if it's not supported
850     if (!bcutils::isSupported(mProperties, sel)) {
851         EXPECT_EQ(result.getServiceSpecificError(), resultToInt(Result::NOT_SUPPORTED));
852         return;
853     }
854 
855     // expect a callback if it succeeds
856     EXPECT_TRUE(result.isOk());
857     EXPECT_TRUE(mCallback->waitOnCurrentProgramInfoChangedCallback());
858     ProgramInfo infoCb = mCallback->getCurrentProgramInfo();
859 
860     LOG(DEBUG) << "Current program info: " << infoCb.toString();
861 
862     // it should tune exactly to what was requested
863     vector<int64_t> freqs = bcutils::getAllIds(infoCb.selector, IdentifierType::DAB_FREQUENCY_KHZ);
864     EXPECT_NE(freqs.end(), find(freqs.begin(), freqs.end(), freq))
865             << "DAB freq " << freq << " kHz is not sent back by callback.";
866 }
867 
868 /**
869  * Test seeking to next/prev station via IBroadcastRadio::seek().
870  *
871  * Verifies that:
872  *  - the method succeeds;
873  *  - the program info is changed within kTuneTimeoutMs;
874  *  - works both directions and with or without ing sub-channel.
875  */
TEST_P(BroadcastRadioHalTest,Seek)876 TEST_P(BroadcastRadioHalTest, Seek) {
877     LOG(DEBUG) << "Seek Test";
878 
879     mCallback->reset();
880 
881     auto result = mModule->seek(/* in_directionUp= */ true, /* in_skipSubChannel= */ true);
882 
883     if (result.getServiceSpecificError() == resultToInt(Result::NOT_SUPPORTED)) {
884         GTEST_SKIP() << "Seek not supported";
885     }
886 
887     EXPECT_TRUE(result.isOk());
888     EXPECT_TRUE(mCallback->waitOnCurrentProgramInfoChangedCallback());
889 
890     mCallback->reset();
891 
892     result = mModule->seek(/* in_directionUp= */ false, /* in_skipSubChannel= */ false);
893 
894     EXPECT_TRUE(result.isOk());
895     EXPECT_TRUE(mCallback->waitOnCurrentProgramInfoChangedCallback());
896 }
897 
898 /**
899  * Test seeking without tuner callback set.
900  *
901  * Verifies that:
902  *  - No tuner callback set results in INVALID_STATE.
903  */
TEST_P(BroadcastRadioHalTest,SeekFailsWithoutTunerCallback)904 TEST_P(BroadcastRadioHalTest, SeekFailsWithoutTunerCallback) {
905     LOG(DEBUG) << "SeekFailsWithoutTunerCallback Test";
906 
907     mModule->unsetTunerCallback();
908 
909     auto result = mModule->seek(/* in_directionUp= */ true, /* in_skipSubChannel= */ true);
910 
911     EXPECT_EQ(result.getServiceSpecificError(), resultToInt(Result::INVALID_STATE));
912 
913     result = mModule->seek(/* in_directionUp= */ false, /* in_skipSubChannel= */ false);
914 
915     EXPECT_EQ(result.getServiceSpecificError(), resultToInt(Result::INVALID_STATE));
916 }
917 
918 /**
919  * Test step operation.
920  *
921  * Verifies that:
922  *  - the method succeeds or returns NOT_SUPPORTED;
923  *  - the program info is changed within kTuneTimeoutMs if the method succeeded;
924  *  - works both directions.
925  */
TEST_P(BroadcastRadioHalTest,Step)926 TEST_P(BroadcastRadioHalTest, Step) {
927     LOG(DEBUG) << "Step Test";
928 
929     mCallback->reset();
930 
931     auto result = mModule->step(/* in_directionUp= */ true);
932 
933     if (result.getServiceSpecificError() == resultToInt(Result::NOT_SUPPORTED)) {
934         GTEST_SKIP() << "Step not supported";
935     }
936     EXPECT_TRUE(result.isOk());
937     EXPECT_TRUE(mCallback->waitOnCurrentProgramInfoChangedCallback());
938 
939     mCallback->reset();
940 
941     result = mModule->step(/* in_directionUp= */ false);
942 
943     EXPECT_TRUE(result.isOk());
944     EXPECT_TRUE(mCallback->waitOnCurrentProgramInfoChangedCallback());
945 }
946 
947 /**
948  * Test step operation without tuner callback set.
949  *
950  * Verifies that:
951  *  - No tuner callback set results in INVALID_STATE.
952  */
TEST_P(BroadcastRadioHalTest,StepFailsWithoutTunerCallback)953 TEST_P(BroadcastRadioHalTest, StepFailsWithoutTunerCallback) {
954     LOG(DEBUG) << "StepFailsWithoutTunerCallback Test";
955 
956     mModule->unsetTunerCallback();
957 
958     auto result = mModule->step(/* in_directionUp= */ true);
959 
960     EXPECT_EQ(result.getServiceSpecificError(), resultToInt(Result::INVALID_STATE));
961 
962     result = mModule->step(/* in_directionUp= */ false);
963 
964     EXPECT_EQ(result.getServiceSpecificError(), resultToInt(Result::INVALID_STATE));
965 }
966 
967 /**
968  * Test tune cancellation.
969  *
970  * Verifies that:
971  *  - the method does not crash after being invoked multiple times.
972  *
973  * Since cancel() might be called after the HAL completes an operation (tune, seek, and step)
974  * and before the callback completions, the operation might not be actually canceled and the
975  * effect of cancel() is not deterministic to be tested here.
976  */
TEST_P(BroadcastRadioHalTest,Cancel)977 TEST_P(BroadcastRadioHalTest, Cancel) {
978     LOG(DEBUG) << "Cancel Test";
979 
980     auto notSupportedError = resultToInt(Result::NOT_SUPPORTED);
981     for (int i = 0; i < 10; i++) {
982         auto result = mModule->seek(/* in_directionUp= */ true, /* in_skipSubChannel= */ true);
983 
984         if (result.getServiceSpecificError() == notSupportedError) {
985             GTEST_SKIP() << "Cancel is skipped because of seek not supported";
986         }
987         EXPECT_TRUE(result.isOk());
988 
989         auto cancelResult = mModule->cancel();
990 
991         ASSERT_TRUE(cancelResult.isOk());
992     }
993 }
994 
995 /**
996  * Test IBroadcastRadio::get|setParameters() methods called with no parameters.
997  *
998  * Verifies that:
999  *  - callback is called for empty parameters set.
1000  */
TEST_P(BroadcastRadioHalTest,NoParameters)1001 TEST_P(BroadcastRadioHalTest, NoParameters) {
1002     LOG(DEBUG) << "NoParameters Test";
1003 
1004     vector<VendorKeyValue> parametersResults = {};
1005 
1006     auto halResult = mModule->setParameters({}, &parametersResults);
1007 
1008     ASSERT_TRUE(halResult.isOk());
1009     ASSERT_EQ(parametersResults.size(), 0u);
1010 
1011     parametersResults.clear();
1012 
1013     halResult = mModule->getParameters({}, &parametersResults);
1014 
1015     ASSERT_TRUE(halResult.isOk());
1016     ASSERT_EQ(parametersResults.size(), 0u);
1017 }
1018 
1019 /**
1020  * Test IBroadcastRadio::get|setParameters() methods called with unknown parameters.
1021  *
1022  * Verifies that:
1023  *  - unknown parameters are ignored;
1024  *  - callback is called also for empty results set.
1025  */
TEST_P(BroadcastRadioHalTest,UnknownParameters)1026 TEST_P(BroadcastRadioHalTest, UnknownParameters) {
1027     LOG(DEBUG) << "UnknownParameters Test";
1028 
1029     vector<VendorKeyValue> parametersResults = {};
1030 
1031     auto halResult =
1032             mModule->setParameters({{"com.android.unknown", "sample"}}, &parametersResults);
1033 
1034     ASSERT_TRUE(halResult.isOk());
1035     ASSERT_EQ(parametersResults.size(), 0u);
1036 
1037     parametersResults.clear();
1038 
1039     halResult = mModule->getParameters({"com.android.unknown*", "sample"}, &parametersResults);
1040 
1041     ASSERT_TRUE(halResult.isOk());
1042     ASSERT_EQ(parametersResults.size(), 0u);
1043 }
1044 
1045 /**
1046  * Test geting image of invalid ID.
1047  *
1048  * Verifies that:
1049  * - getImage call handles argument 0 gracefully.
1050  */
TEST_P(BroadcastRadioHalTest,GetNoImage)1051 TEST_P(BroadcastRadioHalTest, GetNoImage) {
1052     LOG(DEBUG) << "GetNoImage Test";
1053     vector<uint8_t> rawImage;
1054 
1055     auto result = mModule->getImage(IBroadcastRadio::INVALID_IMAGE, &rawImage);
1056 
1057     ASSERT_TRUE(result.isOk());
1058     ASSERT_EQ(rawImage.size(), 0u);
1059 }
1060 
1061 /**
1062  * Test getting config flags.
1063  *
1064  * Verifies that:
1065  * - isConfigFlagSet either succeeds or ends with NOT_SUPPORTED or INVALID_STATE;
1066  * - call success or failure is consistent with setConfigFlag.
1067  */
TEST_P(BroadcastRadioHalTest,FetchConfigFlags)1068 TEST_P(BroadcastRadioHalTest, FetchConfigFlags) {
1069     LOG(DEBUG) << "FetchConfigFlags Test";
1070 
1071     for (const auto& flag : kConfigFlagValues) {
1072         bool gotValue = false;
1073 
1074         auto halResult = mModule->isConfigFlagSet(flag, &gotValue);
1075 
1076         if (halResult.getServiceSpecificError() != resultToInt(Result::NOT_SUPPORTED) &&
1077             halResult.getServiceSpecificError() != resultToInt(Result::INVALID_STATE)) {
1078             ASSERT_TRUE(halResult.isOk());
1079         }
1080 
1081         // set must fail or succeed the same way as get
1082         auto setResult = mModule->setConfigFlag(flag, /* value= */ false);
1083 
1084         EXPECT_TRUE((halResult.isOk() && setResult.isOk()) ||
1085                     (halResult.getServiceSpecificError()) == setResult.getServiceSpecificError());
1086 
1087         setResult = mModule->setConfigFlag(flag, /* value= */ true);
1088 
1089         EXPECT_TRUE((halResult.isOk() && setResult.isOk()) ||
1090                     (halResult.getServiceSpecificError()) == setResult.getServiceSpecificError());
1091     }
1092 }
1093 
1094 /**
1095  * Test setting config flags.
1096  *
1097  * Verifies that:
1098  * - setConfigFlag either succeeds or ends with NOT_SUPPORTED or INVALID_STATE;
1099  * - isConfigFlagSet reflects the state requested immediately after the set call.
1100  */
TEST_P(BroadcastRadioHalTest,SetConfigFlags)1101 TEST_P(BroadcastRadioHalTest, SetConfigFlags) {
1102     LOG(DEBUG) << "SetConfigFlags Test";
1103 
1104     auto get = [&](ConfigFlag flag) -> bool {
1105         bool gotValue;
1106 
1107         auto halResult = mModule->isConfigFlagSet(flag, &gotValue);
1108 
1109         EXPECT_TRUE(halResult.isOk());
1110         return gotValue;
1111     };
1112 
1113     auto notSupportedError = resultToInt(Result::NOT_SUPPORTED);
1114     auto invalidStateError = resultToInt(Result::INVALID_STATE);
1115     for (const auto& flag : kConfigFlagValues) {
1116         auto result = mModule->setConfigFlag(flag, /* value= */ false);
1117 
1118         if (result.getServiceSpecificError() == notSupportedError ||
1119             result.getServiceSpecificError() == invalidStateError) {
1120             // setting to true must result in the same error as false
1121             auto secondResult = mModule->setConfigFlag(flag, /* value= */ true);
1122 
1123             EXPECT_TRUE((result.isOk() && secondResult.isOk()) ||
1124                         result.getServiceSpecificError() == secondResult.getServiceSpecificError());
1125             continue;
1126         } else {
1127             ASSERT_TRUE(result.isOk());
1128         }
1129 
1130         // verify false is set
1131         bool value = get(flag);
1132         EXPECT_FALSE(value);
1133 
1134         // try setting true this time
1135         result = mModule->setConfigFlag(flag, /* value= */ true);
1136 
1137         ASSERT_TRUE(result.isOk());
1138         value = get(flag);
1139         EXPECT_TRUE(value);
1140 
1141         // false again
1142         result = mModule->setConfigFlag(flag, /* value= */ false);
1143 
1144         ASSERT_TRUE(result.isOk());
1145         value = get(flag);
1146         EXPECT_FALSE(value);
1147     }
1148 }
1149 
1150 /**
1151  * Test getting program list using empty program filter.
1152  *
1153  * Verifies that:
1154  * - startProgramListUpdates either succeeds or returns NOT_SUPPORTED;
1155  * - the complete list is fetched within kProgramListScanTimeoutMs;
1156  * - stopProgramListUpdates does not crash;
1157  * - metadata of program info in the program list is valid;
1158  * - alert message is valid if it exists in the program list.
1159  */
TEST_P(BroadcastRadioHalTest,GetProgramListFromEmptyFilter)1160 TEST_P(BroadcastRadioHalTest, GetProgramListFromEmptyFilter) {
1161     LOG(DEBUG) << "GetProgramListFromEmptyFilter Test";
1162 
1163     std::optional<bcutils::ProgramInfoSet> completeList = getProgramList();
1164 
1165     if (!completeList || mAidlVersion < kAidlVersion3) {
1166         return;
1167     }
1168     for (const auto& program : *completeList) {
1169         validateMetadata(program, mAidlVersion);
1170         validateAlert(program, mAidlVersion);
1171     }
1172 }
1173 
1174 /**
1175  * Test getting program list using AMFM frequency program filter.
1176  *
1177  * Verifies that:
1178  * - startProgramListUpdates either succeeds or returns NOT_SUPPORTED;
1179  * - the complete list is fetched within kProgramListScanTimeoutMs;
1180  * - stopProgramListUpdates does not crash;
1181  * - result for startProgramListUpdates using a filter with AMFM_FREQUENCY_KHZ value of the first
1182  *   AMFM program matches the expected result.
1183  */
TEST_P(BroadcastRadioHalTest,GetProgramListFromAmFmFilter)1184 TEST_P(BroadcastRadioHalTest, GetProgramListFromAmFmFilter) {
1185     LOG(DEBUG) << "GetProgramListFromAmFmFilter Test";
1186 
1187     std::optional<bcutils::ProgramInfoSet> completeList = getProgramList();
1188     if (!completeList) {
1189         GTEST_SKIP() << "No program list available";
1190     }
1191 
1192     ProgramFilter amfmFilter = {};
1193     int expectedResultSize = 0;
1194     uint64_t expectedFreq = 0;
1195     for (const auto& program : *completeList) {
1196         vector<int64_t> amfmIds =
1197                 bcutils::getAllIds(program.selector, IdentifierType::AMFM_FREQUENCY_KHZ);
1198         EXPECT_LE(amfmIds.size(), 1u);
1199         if (amfmIds.size() == 0) {
1200             continue;
1201         }
1202 
1203         if (expectedResultSize == 0) {
1204             expectedFreq = amfmIds[0];
1205             amfmFilter.identifiers = {
1206                     makeIdentifier(IdentifierType::AMFM_FREQUENCY_KHZ, expectedFreq)};
1207             expectedResultSize = 1;
1208         } else if (amfmIds[0] == expectedFreq) {
1209             expectedResultSize++;
1210         }
1211     }
1212 
1213     if (expectedResultSize == 0) {
1214         GTEST_SKIP() << "No Am/FM programs available";
1215     }
1216     std::optional<bcutils::ProgramInfoSet> amfmList = getProgramList(amfmFilter);
1217     ASSERT_EQ(amfmList->size(), expectedResultSize) << "amfm filter result size is wrong";
1218 }
1219 
1220 /**
1221  * Test getting program list using DAB ensemble program filter.
1222  *
1223  * Verifies that:
1224  * - startProgramListUpdates either succeeds or returns NOT_SUPPORTED;
1225  * - the complete list is fetched within kProgramListScanTimeoutMs;
1226  * - stopProgramListUpdates does not crash;
1227  * - result for startProgramListUpdates using a filter with DAB_ENSEMBLE value of the first DAB
1228  *   program matches the expected result.
1229  */
TEST_P(BroadcastRadioHalTest,GetProgramListFromDabFilter)1230 TEST_P(BroadcastRadioHalTest, GetProgramListFromDabFilter) {
1231     LOG(DEBUG) << "GetProgramListFromDabFilter Test";
1232 
1233     std::optional<bcutils::ProgramInfoSet> completeList = getProgramList();
1234     if (!completeList) {
1235         GTEST_SKIP() << "No program list available";
1236     }
1237 
1238     ProgramFilter dabFilter = {};
1239     int expectedResultSize = 0;
1240     uint64_t expectedEnsemble = 0;
1241     for (const auto& program : *completeList) {
1242         auto dabEnsembles = bcutils::getAllIds(program.selector, IdentifierType::DAB_ENSEMBLE);
1243         EXPECT_LE(dabEnsembles.size(), 1u);
1244         if (dabEnsembles.size() == 0) {
1245             continue;
1246         }
1247 
1248         if (expectedResultSize == 0) {
1249             expectedEnsemble = dabEnsembles[0];
1250             dabFilter.identifiers = {
1251                     makeIdentifier(IdentifierType::DAB_ENSEMBLE, expectedEnsemble)};
1252             expectedResultSize = 1;
1253         } else if (dabEnsembles[0] == expectedEnsemble) {
1254             expectedResultSize++;
1255         }
1256     }
1257 
1258     if (expectedResultSize == 0) {
1259         GTEST_SKIP() << "No DAB programs available";
1260     }
1261     std::optional<bcutils::ProgramInfoSet> dabList = getProgramList(dabFilter);
1262     ASSERT_EQ(dabList->size(), expectedResultSize) << "dab filter result size is wrong";
1263 }
1264 
1265 /**
1266  * Test HD_STATION_NAME correctness.
1267  *
1268  * Verifies that if a program on the list contains HD_STATION_NAME identifier:
1269  *  - the program provides station name in its metadata;
1270  *  - the identifier matches the name;
1271  *  - there is only one identifier of that type.
1272  */
TEST_P(BroadcastRadioHalTest,HdRadioStationNameId)1273 TEST_P(BroadcastRadioHalTest, HdRadioStationNameId) {
1274     LOG(DEBUG) << "HdRadioStationNameId Test";
1275 
1276     std::optional<bcutils::ProgramInfoSet> list = getProgramList();
1277     if (!list) {
1278         GTEST_SKIP() << "No program list";
1279     }
1280 
1281     for (const auto& program : *list) {
1282         vector<int64_t> nameIds =
1283                 bcutils::getAllIds(program.selector, IdentifierType::HD_STATION_NAME);
1284         EXPECT_LE(nameIds.size(), 1u);
1285         if (nameIds.size() == 0) {
1286             continue;
1287         }
1288 
1289         std::optional<std::string> name;
1290         if (mAidlVersion == kAidlVersion1) {
1291             name = bcutils::getMetadataString(program, Metadata::programName);
1292             if (!name) {
1293                 name = bcutils::getMetadataString(program, Metadata::rdsPs);
1294             }
1295         } else if (mAidlVersion == kAidlVersion2) {
1296             name = bcutils::getMetadataStringV2(program, Metadata::programName);
1297             if (!name) {
1298                 name = bcutils::getMetadataStringV2(program, Metadata::rdsPs);
1299             }
1300         } else {
1301             LOG(ERROR) << "Unknown HAL AIDL version " << mAidlVersion;
1302         }
1303 
1304         ASSERT_TRUE(name.has_value());
1305 
1306         ProgramIdentifier expectedId = bcutils::makeHdRadioStationName(*name);
1307         EXPECT_EQ(nameIds[0], expectedId.value);
1308     }
1309 }
1310 
1311 /**
1312  * Test announcement listener registration.
1313  *
1314  * Verifies that:
1315  *  - registerAnnouncementListener either succeeds or returns NOT_SUPPORTED;
1316  *  - if it succeeds, it returns a valid close handle (which is a nullptr otherwise);
1317  *  - closing handle does not crash.
1318  */
TEST_P(BroadcastRadioHalTest,AnnouncementListenerRegistration)1319 TEST_P(BroadcastRadioHalTest, AnnouncementListenerRegistration) {
1320     LOG(DEBUG) << "AnnouncementListenerRegistration Test";
1321     std::shared_ptr<AnnouncementListenerMock> listener =
1322             SharedRefBase::make<AnnouncementListenerMock>();
1323     std::shared_ptr<ICloseHandle> closeHandle = nullptr;
1324 
1325     auto halResult = mModule->registerAnnouncementListener(listener, {AnnouncementType::EMERGENCY},
1326                                                            &closeHandle);
1327 
1328     if (halResult.getServiceSpecificError() == resultToInt(Result::NOT_SUPPORTED)) {
1329         ASSERT_EQ(closeHandle.get(), nullptr);
1330         GTEST_SKIP() << "Announcements not supported";
1331     }
1332 
1333     ASSERT_TRUE(halResult.isOk());
1334     ASSERT_NE(closeHandle.get(), nullptr);
1335 
1336     closeHandle->close();
1337 }
1338 
1339 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(BroadcastRadioHalTest);
1340 INSTANTIATE_TEST_SUITE_P(
1341         PerInstance, BroadcastRadioHalTest,
1342         testing::ValuesIn(::android::getAidlHalInstanceNames(IBroadcastRadio::descriptor)),
1343         ::android::PrintInstanceNameToString);
1344 
1345 }  // namespace aidl::android::hardware::broadcastradio::vts
1346 
main(int argc,char ** argv)1347 int main(int argc, char** argv) {
1348     android::base::SetDefaultTag("BcRadio.vts");
1349     android::base::SetMinimumLogSeverity(android::base::VERBOSE);
1350     ::testing::InitGoogleTest(&argc, argv);
1351     ABinderProcess_setThreadPoolMaxThreadCount(4);
1352     ABinderProcess_startThreadPool();
1353     return RUN_ALL_TESTS();
1354 }
1355