blob: 79d3e60e8d4729d655c29af22b22fdb94c203d66 [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/**
Weilin Xu3bab6132023-12-06 16:07:43 -0800705 * Test tuning with HD selector.
706 *
707 * Verifies that:
708 * - if AM/FM HD 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 to a program info with the program selector requested.
713 */
714TEST_P(BroadcastRadioHalTest, HdTune) {
715 LOG(DEBUG) << "HdTune Test";
716 auto programList = getProgramList();
717 if (!programList) {
718 printSkipped("Empty station list, tune cannot be performed");
719 return;
720 }
721 ProgramSelector hdSel = {};
722 ProgramIdentifier physicallyTunedToExpected = {};
723 bool hdStationPresent = false;
724 for (auto&& programInfo : *programList) {
725 if (programInfo.selector.primaryId.type != IdentifierType::HD_STATION_ID_EXT) {
726 continue;
727 }
728 hdSel = programInfo.selector;
729 hdStationPresent = true;
730 physicallyTunedToExpected = bcutils::makeIdentifier(IdentifierType::AMFM_FREQUENCY_KHZ,
731 bcutils::getAmFmFrequency(hdSel));
732 break;
733 }
734 if (!hdStationPresent) {
735 printSkipped("No HD stations in the list, tune cannot be performed");
736 return;
737 }
738
739 // try tuning
740 auto result = mModule->tune(hdSel);
741
742 // expect a failure if it's not supported
743 if (!bcutils::isSupported(mProperties, hdSel)) {
744 EXPECT_EQ(result.getServiceSpecificError(), resultToInt(Result::NOT_SUPPORTED));
745 return;
746 }
747 // expect a callback if it succeeds
748 EXPECT_TRUE(result.isOk());
749 EXPECT_TRUE(mCallback->waitOnCurrentProgramInfoChangedCallback());
750 ProgramInfo infoCb = mCallback->getCurrentProgramInfo();
751 LOG(DEBUG) << "Current program info: " << infoCb.toString();
752 // it should tune exactly to what was requested
753 EXPECT_EQ(infoCb.selector, hdSel);
754 EXPECT_EQ(infoCb.physicallyTunedTo, physicallyTunedToExpected);
755}
756
757/**
Weilin Xub23d0ea2022-05-09 18:26:23 +0000758 * Test tuning with DAB selector.
759 *
760 * Verifies that:
761 * - if DAB selector is not supported, the method returns NOT_SUPPORTED;
762 * - if it is supported, the method succeeds;
763 * - after a successful tune call, onCurrentProgramInfoChanged callback is
764 * invoked carrying a proper selector;
765 * - program changes exactly to what was requested.
766 */
767TEST_P(BroadcastRadioHalTest, DabTune) {
768 LOG(DEBUG) << "DabTune Test";
769 vector<DabTableEntry> config;
770
771 auto halResult = mModule->getDabRegionConfig(&config);
772
773 if (halResult.getServiceSpecificError() == resultToInt(Result::NOT_SUPPORTED)) {
774 printSkipped("DAB not supported");
775 return;
776 }
777 ASSERT_TRUE(halResult.isOk());
778 ASSERT_NE(config.size(), 0U);
779
Weilin Xu0d4207d2022-12-09 00:37:44 +0000780 auto programList = getProgramList();
781
782 if (!programList) {
783 printSkipped("Empty DAB station list, tune cannot be performed");
784 return;
785 }
786
Weilin Xub23d0ea2022-05-09 18:26:23 +0000787 ProgramSelector sel = {};
Weilin Xu0d4207d2022-12-09 00:37:44 +0000788 uint64_t freq = 0;
789 bool dabStationPresent = false;
790 for (auto&& programInfo : *programList) {
791 if (!utils::hasId(programInfo.selector, IdentifierType::DAB_FREQUENCY_KHZ)) {
792 continue;
793 }
794 for (auto&& config_entry : config) {
795 if (config_entry.frequencyKhz ==
796 utils::getId(programInfo.selector, IdentifierType::DAB_FREQUENCY_KHZ, 0)) {
797 freq = config_entry.frequencyKhz;
798 break;
799 }
800 }
801 // Do not trigger a tune request if the programList entry does not contain
802 // a valid DAB frequency.
803 if (freq == 0) {
804 continue;
805 }
806 int64_t dabSidExt = utils::getId(programInfo.selector, IdentifierType::DAB_SID_EXT, 0);
807 int64_t dabEns = utils::getId(programInfo.selector, IdentifierType::DAB_ENSEMBLE, 0);
808 sel = makeSelectorDab(dabSidExt, (int32_t)dabEns, freq);
809 dabStationPresent = true;
810 break;
811 }
812
813 if (!dabStationPresent) {
814 printSkipped("No DAB stations in the list, tune cannot be performed");
815 return;
816 }
Weilin Xub23d0ea2022-05-09 18:26:23 +0000817
818 // try tuning
Weilin Xub23d0ea2022-05-09 18:26:23 +0000819
820 auto result = mModule->tune(sel);
821
822 // expect a failure if it's not supported
823 if (!bcutils::isSupported(mProperties, sel)) {
824 EXPECT_EQ(result.getServiceSpecificError(), resultToInt(Result::NOT_SUPPORTED));
825 return;
826 }
827
828 // expect a callback if it succeeds
829 EXPECT_TRUE(result.isOk());
Weilin Xu4420c1d2023-06-21 22:49:04 +0000830 EXPECT_TRUE(mCallback->waitOnCurrentProgramInfoChangedCallback());
831 ProgramInfo infoCb = mCallback->getCurrentProgramInfo();
832
Weilin Xub23d0ea2022-05-09 18:26:23 +0000833 LOG(DEBUG) << "Current program info: " << infoCb.toString();
834
835 // it should tune exactly to what was requested
836 vector<int> freqs = bcutils::getAllIds(infoCb.selector, IdentifierType::DAB_FREQUENCY_KHZ);
837 EXPECT_NE(freqs.end(), find(freqs.begin(), freqs.end(), freq))
838 << "DAB freq " << freq << " kHz is not sent back by callback.";
Weilin Xub23d0ea2022-05-09 18:26:23 +0000839}
840
841/**
842 * Test seeking to next/prev station via IBroadcastRadio::seek().
843 *
844 * Verifies that:
845 * - the method succeeds;
Weilin Xu4420c1d2023-06-21 22:49:04 +0000846 * - the program info is changed within kTuneTimeoutMs;
Weilin Xub23d0ea2022-05-09 18:26:23 +0000847 * - works both directions and with or without skipping sub-channel.
848 */
849TEST_P(BroadcastRadioHalTest, Seek) {
850 LOG(DEBUG) << "Seek Test";
851
Weilin Xu4420c1d2023-06-21 22:49:04 +0000852 mCallback->reset();
Weilin Xub23d0ea2022-05-09 18:26:23 +0000853
854 auto result = mModule->seek(/* in_directionUp= */ true, /* in_skipSubChannel= */ true);
855
856 if (result.getServiceSpecificError() == resultToInt(Result::NOT_SUPPORTED)) {
857 printSkipped("Seek not supported");
858 return;
859 }
860
861 EXPECT_TRUE(result.isOk());
Weilin Xu4420c1d2023-06-21 22:49:04 +0000862 EXPECT_TRUE(mCallback->waitOnCurrentProgramInfoChangedCallback());
Weilin Xub23d0ea2022-05-09 18:26:23 +0000863
Weilin Xu4420c1d2023-06-21 22:49:04 +0000864 mCallback->reset();
Weilin Xub23d0ea2022-05-09 18:26:23 +0000865
866 result = mModule->seek(/* in_directionUp= */ false, /* in_skipSubChannel= */ false);
867
868 EXPECT_TRUE(result.isOk());
Weilin Xu4420c1d2023-06-21 22:49:04 +0000869 EXPECT_TRUE(mCallback->waitOnCurrentProgramInfoChangedCallback());
Weilin Xub23d0ea2022-05-09 18:26:23 +0000870}
871
872/**
873 * Test seeking without tuner callback set.
874 *
875 * Verifies that:
876 * - No tuner callback set results in INVALID_STATE.
877 */
878TEST_P(BroadcastRadioHalTest, SeekFailsWithoutTunerCallback) {
879 LOG(DEBUG) << "SeekFailsWithoutTunerCallback Test";
880
881 mModule->unsetTunerCallback();
882
883 auto result = mModule->seek(/* in_directionUp= */ true, /* in_skipSubChannel= */ true);
884
885 EXPECT_EQ(result.getServiceSpecificError(), resultToInt(Result::INVALID_STATE));
886
887 result = mModule->seek(/* in_directionUp= */ false, /* in_skipSubChannel= */ false);
888
889 EXPECT_EQ(result.getServiceSpecificError(), resultToInt(Result::INVALID_STATE));
890}
891
892/**
893 * Test step operation.
894 *
895 * Verifies that:
896 * - the method succeeds or returns NOT_SUPPORTED;
Weilin Xu4420c1d2023-06-21 22:49:04 +0000897 * - the program info is changed within kTuneTimeoutMs if the method succeeded;
Weilin Xub23d0ea2022-05-09 18:26:23 +0000898 * - works both directions.
899 */
900TEST_P(BroadcastRadioHalTest, Step) {
901 LOG(DEBUG) << "Step Test";
902
Weilin Xu4420c1d2023-06-21 22:49:04 +0000903 mCallback->reset();
Weilin Xub23d0ea2022-05-09 18:26:23 +0000904
905 auto result = mModule->step(/* in_directionUp= */ true);
906
907 if (result.getServiceSpecificError() == resultToInt(Result::NOT_SUPPORTED)) {
908 printSkipped("Step not supported");
909 return;
910 }
911 EXPECT_TRUE(result.isOk());
Weilin Xu4420c1d2023-06-21 22:49:04 +0000912 EXPECT_TRUE(mCallback->waitOnCurrentProgramInfoChangedCallback());
Weilin Xub23d0ea2022-05-09 18:26:23 +0000913
Weilin Xu4420c1d2023-06-21 22:49:04 +0000914 mCallback->reset();
Weilin Xub23d0ea2022-05-09 18:26:23 +0000915
916 result = mModule->step(/* in_directionUp= */ false);
917
918 EXPECT_TRUE(result.isOk());
Weilin Xu4420c1d2023-06-21 22:49:04 +0000919 EXPECT_TRUE(mCallback->waitOnCurrentProgramInfoChangedCallback());
Weilin Xub23d0ea2022-05-09 18:26:23 +0000920}
921
922/**
923 * Test step operation without tuner callback set.
924 *
925 * Verifies that:
926 * - No tuner callback set results in INVALID_STATE.
927 */
928TEST_P(BroadcastRadioHalTest, StepFailsWithoutTunerCallback) {
929 LOG(DEBUG) << "StepFailsWithoutTunerCallback Test";
930
931 mModule->unsetTunerCallback();
932
933 auto result = mModule->step(/* in_directionUp= */ true);
934
935 EXPECT_EQ(result.getServiceSpecificError(), resultToInt(Result::INVALID_STATE));
936
937 result = mModule->step(/* in_directionUp= */ false);
938
939 EXPECT_EQ(result.getServiceSpecificError(), resultToInt(Result::INVALID_STATE));
940}
941
942/**
943 * Test tune cancellation.
944 *
945 * Verifies that:
946 * - the method does not crash after being invoked multiple times.
947 *
948 * Since cancel() might be called after the HAL completes an operation (tune, seek, and step)
949 * and before the callback completions, the operation might not be actually canceled and the
950 * effect of cancel() is not deterministic to be tested here.
951 */
952TEST_P(BroadcastRadioHalTest, Cancel) {
953 LOG(DEBUG) << "Cancel Test";
954
955 auto notSupportedError = resultToInt(Result::NOT_SUPPORTED);
956 for (int i = 0; i < 10; i++) {
957 auto result = mModule->seek(/* in_directionUp= */ true, /* in_skipSubChannel= */ true);
958
959 if (result.getServiceSpecificError() == notSupportedError) {
960 printSkipped("Cancel is skipped because of seek not supported");
961 return;
962 }
963 EXPECT_TRUE(result.isOk());
964
965 auto cancelResult = mModule->cancel();
966
967 ASSERT_TRUE(cancelResult.isOk());
968 }
969}
970
971/**
Weilin Xu3277a212022-09-01 19:08:17 +0000972 * Test IBroadcastRadio::get|setParameters() methods called with no parameters.
973 *
974 * Verifies that:
975 * - callback is called for empty parameters set.
976 */
977TEST_P(BroadcastRadioHalTest, NoParameters) {
978 LOG(DEBUG) << "NoParameters Test";
979
980 vector<VendorKeyValue> parametersResults = {};
981
982 auto halResult = mModule->setParameters({}, &parametersResults);
983
984 ASSERT_TRUE(halResult.isOk());
985 ASSERT_EQ(parametersResults.size(), 0u);
986
987 parametersResults.clear();
988
989 halResult = mModule->getParameters({}, &parametersResults);
990
991 ASSERT_TRUE(halResult.isOk());
992 ASSERT_EQ(parametersResults.size(), 0u);
993}
994
995/**
996 * Test IBroadcastRadio::get|setParameters() methods called with unknown parameters.
997 *
998 * Verifies that:
999 * - unknown parameters are ignored;
1000 * - callback is called also for empty results set.
1001 */
1002TEST_P(BroadcastRadioHalTest, UnknownParameters) {
1003 LOG(DEBUG) << "UnknownParameters Test";
1004
1005 vector<VendorKeyValue> parametersResults = {};
1006
1007 auto halResult =
1008 mModule->setParameters({{"com.android.unknown", "sample"}}, &parametersResults);
1009
1010 ASSERT_TRUE(halResult.isOk());
1011 ASSERT_EQ(parametersResults.size(), 0u);
1012
1013 parametersResults.clear();
1014
1015 halResult = mModule->getParameters({"com.android.unknown*", "sample"}, &parametersResults);
1016
1017 ASSERT_TRUE(halResult.isOk());
1018 ASSERT_EQ(parametersResults.size(), 0u);
1019}
1020
1021/**
1022 * Test geting image of invalid ID.
1023 *
1024 * Verifies that:
1025 * - getImage call handles argument 0 gracefully.
1026 */
1027TEST_P(BroadcastRadioHalTest, GetNoImage) {
1028 LOG(DEBUG) << "GetNoImage Test";
1029 vector<uint8_t> rawImage;
1030
1031 auto result = mModule->getImage(IBroadcastRadio::INVALID_IMAGE, &rawImage);
1032
1033 ASSERT_TRUE(result.isOk());
1034 ASSERT_EQ(rawImage.size(), 0u);
1035}
1036
1037/**
1038 * Test getting config flags.
1039 *
1040 * Verifies that:
1041 * - isConfigFlagSet either succeeds or ends with NOT_SUPPORTED or INVALID_STATE;
1042 * - call success or failure is consistent with setConfigFlag.
1043 */
1044TEST_P(BroadcastRadioHalTest, FetchConfigFlags) {
1045 LOG(DEBUG) << "FetchConfigFlags Test";
1046
1047 for (const auto& flag : kConfigFlagValues) {
1048 bool gotValue = false;
1049
1050 auto halResult = mModule->isConfigFlagSet(flag, &gotValue);
1051
1052 if (halResult.getServiceSpecificError() != resultToInt(Result::NOT_SUPPORTED) &&
1053 halResult.getServiceSpecificError() != resultToInt(Result::INVALID_STATE)) {
1054 ASSERT_TRUE(halResult.isOk());
1055 }
1056
1057 // set must fail or succeed the same way as get
1058 auto setResult = mModule->setConfigFlag(flag, /* value= */ false);
1059
1060 EXPECT_TRUE((halResult.isOk() && setResult.isOk()) ||
1061 (halResult.getServiceSpecificError()) == setResult.getServiceSpecificError());
1062
1063 setResult = mModule->setConfigFlag(flag, /* value= */ true);
1064
1065 EXPECT_TRUE((halResult.isOk() && setResult.isOk()) ||
1066 (halResult.getServiceSpecificError()) == setResult.getServiceSpecificError());
1067 }
1068}
1069
1070/**
1071 * Test setting config flags.
1072 *
1073 * Verifies that:
1074 * - setConfigFlag either succeeds or ends with NOT_SUPPORTED or INVALID_STATE;
1075 * - isConfigFlagSet reflects the state requested immediately after the set call.
1076 */
1077TEST_P(BroadcastRadioHalTest, SetConfigFlags) {
1078 LOG(DEBUG) << "SetConfigFlags Test";
1079
1080 auto get = [&](ConfigFlag flag) -> bool {
Weilin Xu978de0a2023-07-19 17:20:19 +00001081 bool gotValue;
Weilin Xu3277a212022-09-01 19:08:17 +00001082
Weilin Xu978de0a2023-07-19 17:20:19 +00001083 auto halResult = mModule->isConfigFlagSet(flag, &gotValue);
Weilin Xu3277a212022-09-01 19:08:17 +00001084
Weilin Xu3277a212022-09-01 19:08:17 +00001085 EXPECT_TRUE(halResult.isOk());
Weilin Xu978de0a2023-07-19 17:20:19 +00001086 return gotValue;
Weilin Xu3277a212022-09-01 19:08:17 +00001087 };
1088
1089 auto notSupportedError = resultToInt(Result::NOT_SUPPORTED);
1090 auto invalidStateError = resultToInt(Result::INVALID_STATE);
1091 for (const auto& flag : kConfigFlagValues) {
1092 auto result = mModule->setConfigFlag(flag, /* value= */ false);
1093
1094 if (result.getServiceSpecificError() == notSupportedError ||
1095 result.getServiceSpecificError() == invalidStateError) {
1096 // setting to true must result in the same error as false
1097 auto secondResult = mModule->setConfigFlag(flag, /* value= */ true);
1098
1099 EXPECT_TRUE((result.isOk() && secondResult.isOk()) ||
1100 result.getServiceSpecificError() == secondResult.getServiceSpecificError());
1101 continue;
1102 } else {
1103 ASSERT_TRUE(result.isOk());
1104 }
1105
1106 // verify false is set
1107 bool value = get(flag);
1108 EXPECT_FALSE(value);
1109
1110 // try setting true this time
1111 result = mModule->setConfigFlag(flag, /* value= */ true);
1112
1113 ASSERT_TRUE(result.isOk());
1114 value = get(flag);
1115 EXPECT_TRUE(value);
1116
1117 // false again
1118 result = mModule->setConfigFlag(flag, /* value= */ false);
1119
1120 ASSERT_TRUE(result.isOk());
1121 value = get(flag);
1122 EXPECT_FALSE(value);
1123 }
1124}
1125
1126/**
Weilin Xub23d0ea2022-05-09 18:26:23 +00001127 * Test getting program list using empty program filter.
1128 *
1129 * Verifies that:
1130 * - startProgramListUpdates either succeeds or returns NOT_SUPPORTED;
Weilin Xu4420c1d2023-06-21 22:49:04 +00001131 * - the complete list is fetched within kProgramListScanTimeoutMs;
Weilin Xub23d0ea2022-05-09 18:26:23 +00001132 * - stopProgramListUpdates does not crash.
1133 */
1134TEST_P(BroadcastRadioHalTest, GetProgramListFromEmptyFilter) {
1135 LOG(DEBUG) << "GetProgramListFromEmptyFilter Test";
1136
1137 getProgramList();
1138}
1139
1140/**
1141 * Test getting program list using AMFM frequency program filter.
1142 *
1143 * Verifies that:
1144 * - startProgramListUpdates either succeeds or returns NOT_SUPPORTED;
Weilin Xu4420c1d2023-06-21 22:49:04 +00001145 * - the complete list is fetched within kProgramListScanTimeoutMs;
Weilin Xub23d0ea2022-05-09 18:26:23 +00001146 * - stopProgramListUpdates does not crash;
1147 * - result for startProgramListUpdates using a filter with AMFM_FREQUENCY_KHZ value of the first
1148 * AMFM program matches the expected result.
1149 */
1150TEST_P(BroadcastRadioHalTest, GetProgramListFromAmFmFilter) {
1151 LOG(DEBUG) << "GetProgramListFromAmFmFilter Test";
1152
1153 std::optional<bcutils::ProgramInfoSet> completeList = getProgramList();
1154 if (!completeList) {
1155 printSkipped("No program list available");
1156 return;
1157 }
1158
1159 ProgramFilter amfmFilter = {};
1160 int expectedResultSize = 0;
1161 uint64_t expectedFreq = 0;
1162 for (const auto& program : *completeList) {
1163 vector<int> amfmIds =
1164 bcutils::getAllIds(program.selector, IdentifierType::AMFM_FREQUENCY_KHZ);
1165 EXPECT_LE(amfmIds.size(), 1u);
1166 if (amfmIds.size() == 0) {
1167 continue;
1168 }
1169
1170 if (expectedResultSize == 0) {
1171 expectedFreq = amfmIds[0];
1172 amfmFilter.identifiers = {
1173 makeIdentifier(IdentifierType::AMFM_FREQUENCY_KHZ, expectedFreq)};
1174 expectedResultSize = 1;
1175 } else if (amfmIds[0] == expectedFreq) {
1176 expectedResultSize++;
1177 }
1178 }
1179
1180 if (expectedResultSize == 0) {
1181 printSkipped("No Am/FM programs available");
1182 return;
1183 }
1184 std::optional<bcutils::ProgramInfoSet> amfmList = getProgramList(amfmFilter);
1185 ASSERT_EQ(amfmList->size(), expectedResultSize) << "amfm filter result size is wrong";
1186}
1187
1188/**
1189 * Test getting program list using DAB ensemble program filter.
1190 *
1191 * Verifies that:
1192 * - startProgramListUpdates either succeeds or returns NOT_SUPPORTED;
Weilin Xu4420c1d2023-06-21 22:49:04 +00001193 * - the complete list is fetched within kProgramListScanTimeoutMs;
Weilin Xub23d0ea2022-05-09 18:26:23 +00001194 * - stopProgramListUpdates does not crash;
1195 * - result for startProgramListUpdates using a filter with DAB_ENSEMBLE value of the first DAB
1196 * program matches the expected result.
1197 */
1198TEST_P(BroadcastRadioHalTest, GetProgramListFromDabFilter) {
1199 LOG(DEBUG) << "GetProgramListFromDabFilter Test";
1200
1201 std::optional<bcutils::ProgramInfoSet> completeList = getProgramList();
1202 if (!completeList) {
1203 printSkipped("No program list available");
1204 return;
1205 }
1206
1207 ProgramFilter dabFilter = {};
1208 int expectedResultSize = 0;
1209 uint64_t expectedEnsemble = 0;
1210 for (const auto& program : *completeList) {
1211 auto dabEnsembles = bcutils::getAllIds(program.selector, IdentifierType::DAB_ENSEMBLE);
1212 EXPECT_LE(dabEnsembles.size(), 1u);
1213 if (dabEnsembles.size() == 0) {
1214 continue;
1215 }
1216
1217 if (expectedResultSize == 0) {
1218 expectedEnsemble = dabEnsembles[0];
1219 dabFilter.identifiers = {
1220 makeIdentifier(IdentifierType::DAB_ENSEMBLE, expectedEnsemble)};
1221 expectedResultSize = 1;
1222 } else if (dabEnsembles[0] == expectedEnsemble) {
1223 expectedResultSize++;
1224 }
1225 }
1226
1227 if (expectedResultSize == 0) {
1228 printSkipped("No DAB programs available");
1229 return;
1230 }
1231 std::optional<bcutils::ProgramInfoSet> dabList = getProgramList(dabFilter);
1232 ASSERT_EQ(dabList->size(), expectedResultSize) << "dab filter result size is wrong";
1233}
1234
Weilin Xu3277a212022-09-01 19:08:17 +00001235/**
1236 * Test HD_STATION_NAME correctness.
1237 *
1238 * Verifies that if a program on the list contains HD_STATION_NAME identifier:
1239 * - the program provides station name in its metadata;
1240 * - the identifier matches the name;
1241 * - there is only one identifier of that type.
1242 */
1243TEST_P(BroadcastRadioHalTest, HdRadioStationNameId) {
1244 LOG(DEBUG) << "HdRadioStationNameId Test";
1245
1246 std::optional<bcutils::ProgramInfoSet> list = getProgramList();
1247 if (!list) {
1248 printSkipped("No program list");
1249 return;
1250 }
1251
1252 for (const auto& program : *list) {
1253 vector<int> nameIds = bcutils::getAllIds(program.selector, IdentifierType::HD_STATION_NAME);
1254 EXPECT_LE(nameIds.size(), 1u);
1255 if (nameIds.size() == 0) {
1256 continue;
1257 }
1258
Weilin Xu25409e52023-09-06 10:36:24 -07001259 std::optional<std::string> name;
1260 if (mAidlVersion == kAidlVersion1) {
1261 name = bcutils::getMetadataString(program, Metadata::programName);
1262 if (!name) {
1263 name = bcutils::getMetadataString(program, Metadata::rdsPs);
1264 }
1265 } else if (mAidlVersion == kAidlVersion2) {
1266 name = bcutils::getMetadataStringV2(program, Metadata::programName);
1267 if (!name) {
1268 name = bcutils::getMetadataStringV2(program, Metadata::rdsPs);
1269 }
1270 } else {
1271 LOG(ERROR) << "Unknown HAL AIDL version " << mAidlVersion;
Weilin Xu3277a212022-09-01 19:08:17 +00001272 }
Weilin Xu25409e52023-09-06 10:36:24 -07001273
Weilin Xu3277a212022-09-01 19:08:17 +00001274 ASSERT_TRUE(name.has_value());
1275
1276 ProgramIdentifier expectedId = bcutils::makeHdRadioStationName(*name);
1277 EXPECT_EQ(nameIds[0], expectedId.value);
1278 }
1279}
1280
1281/**
1282 * Test announcement listener registration.
1283 *
1284 * Verifies that:
1285 * - registerAnnouncementListener either succeeds or returns NOT_SUPPORTED;
1286 * - if it succeeds, it returns a valid close handle (which is a nullptr otherwise);
1287 * - closing handle does not crash.
1288 */
1289TEST_P(BroadcastRadioHalTest, AnnouncementListenerRegistration) {
1290 LOG(DEBUG) << "AnnouncementListenerRegistration Test";
1291 std::shared_ptr<AnnouncementListenerMock> listener =
1292 SharedRefBase::make<AnnouncementListenerMock>();
1293 std::shared_ptr<ICloseHandle> closeHandle = nullptr;
1294
1295 auto halResult = mModule->registerAnnouncementListener(listener, {AnnouncementType::EMERGENCY},
1296 &closeHandle);
1297
1298 if (halResult.getServiceSpecificError() == resultToInt(Result::NOT_SUPPORTED)) {
1299 ASSERT_EQ(closeHandle.get(), nullptr);
1300 printSkipped("Announcements not supported");
1301 return;
1302 }
1303
1304 ASSERT_TRUE(halResult.isOk());
1305 ASSERT_NE(closeHandle.get(), nullptr);
1306
1307 closeHandle->close();
1308}
1309
Weilin Xub23d0ea2022-05-09 18:26:23 +00001310GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(BroadcastRadioHalTest);
1311INSTANTIATE_TEST_SUITE_P(
1312 PerInstance, BroadcastRadioHalTest,
1313 testing::ValuesIn(::android::getAidlHalInstanceNames(IBroadcastRadio::descriptor)),
1314 ::android::PrintInstanceNameToString);
1315
1316} // namespace aidl::android::hardware::broadcastradio::vts
1317
1318int main(int argc, char** argv) {
1319 android::base::SetDefaultTag("BcRadio.vts");
1320 android::base::SetMinimumLogSeverity(android::base::VERBOSE);
1321 ::testing::InitGoogleTest(&argc, argv);
1322 ABinderProcess_setThreadPoolMaxThreadCount(4);
1323 ABinderProcess_startThreadPool();
1324 return RUN_ALL_TESTS();
1325}