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