1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #define LOG_TAG "broadcastradio.vts"
18 
19 #include <android-base/logging.h>
20 #include <android/hardware/broadcastradio/1.1/IBroadcastRadio.h>
21 #include <android/hardware/broadcastradio/1.1/IBroadcastRadioFactory.h>
22 #include <android/hardware/broadcastradio/1.1/ITuner.h>
23 #include <android/hardware/broadcastradio/1.1/ITunerCallback.h>
24 #include <android/hardware/broadcastradio/1.1/types.h>
25 #include <broadcastradio-utils-1x/Utils.h>
26 #include <broadcastradio-vts-utils/call-barrier.h>
27 #include <broadcastradio-vts-utils/hal-1.x-enum-utils.h>
28 #include <broadcastradio-vts-utils/mock-timeout.h>
29 #include <broadcastradio-vts-utils/pointer-utils.h>
30 #include <cutils/native_handle.h>
31 #include <cutils/properties.h>
32 #include <gmock/gmock.h>
33 #include <gtest/gtest.h>
34 #include <hidl/GtestPrinter.h>
35 #include <hidl/HidlTransportSupport.h>
36 #include <hidl/ServiceManagement.h>
37 #include <utils/threads.h>
38 
39 #include <chrono>
40 
41 namespace android {
42 namespace hardware {
43 namespace broadcastradio {
44 namespace V1_1 {
45 namespace vts {
46 
47 using namespace std::chrono_literals;
48 
49 using testing::_;
50 using testing::AnyNumber;
51 using testing::ByMove;
52 using testing::DoAll;
53 using testing::Invoke;
54 using testing::SaveArg;
55 
56 using broadcastradio::V1_0::vts::RadioClassFromString;
57 using broadcastradio::vts::CallBarrier;
58 using V1_0::BandConfig;
59 using V1_0::Class;
60 using V1_0::MetaData;
61 using V1_0::MetadataKey;
62 using V1_0::MetadataType;
63 
64 using broadcastradio::vts::clearAndWait;
65 
66 static constexpr auto kConfigTimeout = 10s;
67 static constexpr auto kConnectModuleTimeout = 1s;
68 static constexpr auto kTuneTimeout = 30s;
69 static constexpr auto kEventPropagationTimeout = 1s;
70 static constexpr auto kFullScanTimeout = 1min;
71 
72 static constexpr ProgramType kStandardProgramTypes[] = {
73     ProgramType::AM,  ProgramType::FM,   ProgramType::AM_HD, ProgramType::FM_HD,
74     ProgramType::DAB, ProgramType::DRMO, ProgramType::SXM};
75 
printSkipped(std::string msg)76 static void printSkipped(std::string msg) {
77     std::cout << "[  SKIPPED ] " << msg << std::endl;
78 }
79 
80 struct TunerCallbackMock : public ITunerCallback {
TunerCallbackMockandroid::hardware::broadcastradio::V1_1::vts::TunerCallbackMock81     TunerCallbackMock() { EXPECT_CALL(*this, hardwareFailure()).Times(0); }
82 
83     MOCK_METHOD0(hardwareFailure, Return<void>());
84     MOCK_TIMEOUT_METHOD2(configChange, Return<void>(Result, const BandConfig&));
85     MOCK_METHOD2(tuneComplete, Return<void>(Result, const V1_0::ProgramInfo&));
86     MOCK_TIMEOUT_METHOD2(tuneComplete_1_1, Return<void>(Result, const ProgramSelector&));
87     MOCK_METHOD1(afSwitch, Return<void>(const V1_0::ProgramInfo&));
88     MOCK_METHOD1(antennaStateChange, Return<void>(bool connected));
89     MOCK_METHOD1(trafficAnnouncement, Return<void>(bool active));
90     MOCK_METHOD1(emergencyAnnouncement, Return<void>(bool active));
91     MOCK_METHOD3(newMetadata, Return<void>(uint32_t ch, uint32_t subCh, const hidl_vec<MetaData>&));
92     MOCK_METHOD1(backgroundScanAvailable, Return<void>(bool));
93     MOCK_TIMEOUT_METHOD1(backgroundScanComplete, Return<void>(ProgramListResult));
94     MOCK_METHOD0(programListChanged, Return<void>());
95     MOCK_TIMEOUT_METHOD1(currentProgramInfoChanged, Return<void>(const ProgramInfo&));
96 };
97 
98 class BroadcastRadioHalTest
99     : public ::testing::TestWithParam<std::tuple<std::string, std::string>> {
100   protected:
101     virtual void SetUp() override;
102     virtual void TearDown() override;
103 
104     bool openTuner();
105     bool nextBand();
106     bool getProgramList(std::function<void(const hidl_vec<ProgramInfo>& list)> cb);
107 
108     Class radioClass;
109     bool skipped = false;
110 
111     sp<IBroadcastRadio> mRadioModule;
112     sp<ITuner> mTuner;
113     sp<TunerCallbackMock> mCallback = new TunerCallbackMock();
114 
115    private:
116     const BandConfig& getBand(unsigned idx);
117 
118     unsigned currentBandIndex = 0;
119     hidl_vec<BandConfig> mBands;
120 };
121 
SetUp()122 void BroadcastRadioHalTest::SetUp() {
123     radioClass = RadioClassFromString(std::get<1>(GetParam()));
124 
125     // lookup HIDL service
126     auto factory = IBroadcastRadioFactory::getService(std::get<0>(GetParam()));
127     ASSERT_NE(nullptr, factory.get());
128 
129     // connect radio module
130     Result connectResult;
131     CallBarrier onConnect;
132     factory->connectModule(radioClass, [&](Result ret, const sp<V1_0::IBroadcastRadio>& radio) {
133         connectResult = ret;
134         if (ret == Result::OK) mRadioModule = IBroadcastRadio::castFrom(radio);
135         onConnect.call();
136     });
137     ASSERT_TRUE(onConnect.waitForCall(kConnectModuleTimeout));
138 
139     if (connectResult == Result::INVALID_ARGUMENTS) {
140         printSkipped("This device class is not supported.");
141         skipped = true;
142         return;
143     }
144     ASSERT_EQ(connectResult, Result::OK);
145     ASSERT_NE(nullptr, mRadioModule.get());
146 
147     // get module properties
148     Properties prop11;
149     auto& prop10 = prop11.base;
150     auto propResult =
151         mRadioModule->getProperties_1_1([&](const Properties& properties) { prop11 = properties; });
152 
153     ASSERT_TRUE(propResult.isOk());
154     EXPECT_EQ(radioClass, prop10.classId);
155     EXPECT_GT(prop10.numTuners, 0u);
156     EXPECT_GT(prop11.supportedProgramTypes.size(), 0u);
157     EXPECT_GT(prop11.supportedIdentifierTypes.size(), 0u);
158     if (radioClass == Class::AM_FM) {
159         EXPECT_GT(prop10.bands.size(), 0u);
160     }
161     mBands = prop10.bands;
162 }
163 
TearDown()164 void BroadcastRadioHalTest::TearDown() {
165     mTuner.clear();
166     mRadioModule.clear();
167     clearAndWait(mCallback, 1s);
168 }
169 
openTuner()170 bool BroadcastRadioHalTest::openTuner() {
171     EXPECT_EQ(nullptr, mTuner.get());
172 
173     if (radioClass == Class::AM_FM) {
174         EXPECT_TIMEOUT_CALL(*mCallback, configChange, Result::OK, _);
175     }
176 
177     Result halResult = Result::NOT_INITIALIZED;
178     auto openCb = [&](Result result, const sp<V1_0::ITuner>& tuner) {
179         halResult = result;
180         if (result != Result::OK) return;
181         mTuner = ITuner::castFrom(tuner);
182     };
183     currentBandIndex = 0;
184     auto hidlResult = mRadioModule->openTuner(getBand(0), true, mCallback, openCb);
185 
186     EXPECT_TRUE(hidlResult.isOk());
187     EXPECT_EQ(Result::OK, halResult);
188     EXPECT_NE(nullptr, mTuner.get());
189     if (radioClass == Class::AM_FM && mTuner != nullptr) {
190         EXPECT_TIMEOUT_CALL_WAIT(*mCallback, configChange, kConfigTimeout);
191 
192         BandConfig halConfig;
193         Result halResult = Result::NOT_INITIALIZED;
194         mTuner->getConfiguration([&](Result result, const BandConfig& config) {
195             halResult = result;
196             halConfig = config;
197         });
198         EXPECT_EQ(Result::OK, halResult);
199         EXPECT_TRUE(halConfig.antennaConnected);
200     }
201 
202     EXPECT_NE(nullptr, mTuner.get());
203     return nullptr != mTuner.get();
204 }
205 
getBand(unsigned idx)206 const BandConfig& BroadcastRadioHalTest::getBand(unsigned idx) {
207     static const BandConfig dummyBandConfig = {};
208 
209     if (radioClass != Class::AM_FM) {
210         ALOGD("Not AM/FM radio, returning dummy band config");
211         return dummyBandConfig;
212     }
213 
214     EXPECT_GT(mBands.size(), idx);
215     if (mBands.size() <= idx) {
216         ALOGD("Band index out of bound, returning dummy band config");
217         return dummyBandConfig;
218     }
219 
220     auto& band = mBands[idx];
221     ALOGD("Returning %s band", toString(band.type).c_str());
222     return band;
223 }
224 
nextBand()225 bool BroadcastRadioHalTest::nextBand() {
226     if (currentBandIndex + 1 >= mBands.size()) return false;
227     currentBandIndex++;
228 
229     BandConfig bandCb;
230     EXPECT_TIMEOUT_CALL(*mCallback, configChange, Result::OK, _)
231         .WillOnce(DoAll(SaveArg<1>(&bandCb), testing::Return(ByMove(Void()))));
232     auto hidlResult = mTuner->setConfiguration(getBand(currentBandIndex));
233     EXPECT_EQ(Result::OK, hidlResult);
234     EXPECT_TIMEOUT_CALL_WAIT(*mCallback, configChange, kConfigTimeout);
235     EXPECT_EQ(getBand(currentBandIndex), bandCb);
236 
237     return true;
238 }
239 
getProgramList(std::function<void (const hidl_vec<ProgramInfo> & list)> cb)240 bool BroadcastRadioHalTest::getProgramList(
241     std::function<void(const hidl_vec<ProgramInfo>& list)> cb) {
242     ProgramListResult getListResult = ProgramListResult::NOT_INITIALIZED;
243     bool isListEmpty = true;
244     auto getListCb = [&](ProgramListResult result, const hidl_vec<ProgramInfo>& list) {
245         ALOGD("getListCb(%s, ProgramInfo[%zu])", toString(result).c_str(), list.size());
246         getListResult = result;
247         if (result != ProgramListResult::OK) return;
248         isListEmpty = (list.size() == 0);
249         if (!isListEmpty) cb(list);
250     };
251 
252     // first try...
253     EXPECT_TIMEOUT_CALL(*mCallback, backgroundScanComplete, ProgramListResult::OK)
254         .Times(AnyNumber());
255     auto hidlResult = mTuner->getProgramList({}, getListCb);
256     EXPECT_TRUE(hidlResult.isOk());
257     if (!hidlResult.isOk()) return false;
258 
259     if (getListResult == ProgramListResult::NOT_STARTED) {
260         auto result = mTuner->startBackgroundScan();
261         EXPECT_EQ(ProgramListResult::OK, result);
262         getListResult = ProgramListResult::NOT_READY;  // continue as in NOT_READY case
263     }
264     if (getListResult == ProgramListResult::NOT_READY) {
265         EXPECT_TIMEOUT_CALL_WAIT(*mCallback, backgroundScanComplete, kFullScanTimeout);
266 
267         // second (last) try...
268         hidlResult = mTuner->getProgramList({}, getListCb);
269         EXPECT_TRUE(hidlResult.isOk());
270         if (!hidlResult.isOk()) return false;
271         EXPECT_EQ(ProgramListResult::OK, getListResult);
272     }
273 
274     return !isListEmpty;
275 }
276 
277 /**
278  * Test IBroadcastRadio::openTuner() method called twice.
279  *
280  * Verifies that:
281  *  - the openTuner method succeeds when called for the second time without
282  *    deleting previous ITuner instance.
283  *
284  * This is a more strict requirement than in 1.0, where a second openTuner
285  * might fail.
286  */
TEST_P(BroadcastRadioHalTest,OpenTunerTwice)287 TEST_P(BroadcastRadioHalTest, OpenTunerTwice) {
288     if (skipped) return;
289 
290     ASSERT_TRUE(openTuner());
291 
292     auto secondTuner = mTuner;
293     mTuner.clear();
294 
295     ASSERT_TRUE(openTuner());
296 }
297 
298 /**
299  * Test tuning to program list entry.
300  *
301  * Verifies that:
302  *  - getProgramList either succeeds or returns NOT_STARTED/NOT_READY status;
303  *  - if the program list is NOT_STARTED, startBackgroundScan makes it completed
304  *    within a full scan timeout and the next getProgramList call succeeds;
305  *  - if the program list is not empty, tuneByProgramSelector call succeeds;
306  *  - getProgramInformation_1_1 returns the same selector as returned in tuneComplete_1_1 call.
307  */
TEST_P(BroadcastRadioHalTest,TuneFromProgramList)308 TEST_P(BroadcastRadioHalTest, TuneFromProgramList) {
309     if (skipped) return;
310     ASSERT_TRUE(openTuner());
311 
312     ProgramInfo firstProgram;
313     bool foundAny = false;
314     do {
315         auto getCb = [&](const hidl_vec<ProgramInfo>& list) {
316             // don't copy the whole list out, it might be heavy
317             firstProgram = list[0];
318         };
319         if (getProgramList(getCb)) foundAny = true;
320     } while (nextBand());
321     if (HasFailure()) return;
322     if (!foundAny) {
323         printSkipped("Program list is empty.");
324         return;
325     }
326 
327     ProgramInfo infoCb;
328     ProgramSelector selCb;
329     EXPECT_CALL(*mCallback, tuneComplete(_, _)).Times(0);
330     EXPECT_TIMEOUT_CALL(*mCallback, tuneComplete_1_1, Result::OK, _)
331         .WillOnce(DoAll(SaveArg<1>(&selCb), testing::Return(ByMove(Void()))));
332     EXPECT_TIMEOUT_CALL(*mCallback, currentProgramInfoChanged, _)
333         .WillOnce(DoAll(SaveArg<0>(&infoCb), testing::Return(ByMove(Void()))));
334     auto tuneResult = mTuner->tuneByProgramSelector(firstProgram.selector);
335     ASSERT_EQ(Result::OK, tuneResult);
336     EXPECT_TIMEOUT_CALL_WAIT(*mCallback, tuneComplete_1_1, kTuneTimeout);
337     EXPECT_TIMEOUT_CALL_WAIT(*mCallback, currentProgramInfoChanged, kEventPropagationTimeout);
338     EXPECT_EQ(firstProgram.selector.primaryId, selCb.primaryId);
339     EXPECT_EQ(infoCb.selector, selCb);
340 
341     bool called = false;
342     auto getResult = mTuner->getProgramInformation_1_1([&](Result result, ProgramInfo info) {
343         called = true;
344         EXPECT_EQ(Result::OK, result);
345         EXPECT_EQ(selCb, info.selector);
346     });
347     ASSERT_TRUE(getResult.isOk());
348     ASSERT_TRUE(called);
349 }
350 
351 /**
352  * Test that primary vendor identifier isn't used for standard program types.
353  *
354  * Verifies that:
355  *  - tuneByProgramSelector fails when VENDORn_PRIMARY is set as a primary
356  *    identifier for program types other than VENDORn.
357  */
TEST_P(BroadcastRadioHalTest,TuneFailsForPrimaryVendor)358 TEST_P(BroadcastRadioHalTest, TuneFailsForPrimaryVendor) {
359     if (skipped) return;
360     ASSERT_TRUE(openTuner());
361 
362     for (auto ptype : kStandardProgramTypes) {
363         ALOGD("Checking %s...", toString(ptype).c_str());
364         ProgramSelector sel = {};
365         sel.programType = static_cast<uint32_t>(ptype);
366         sel.primaryId.type = static_cast<uint32_t>(IdentifierType::VENDOR_PRIMARY_START);
367 
368         auto tuneResult = mTuner->tuneByProgramSelector(sel);
369         ASSERT_NE(Result::OK, tuneResult);
370     }
371 }
372 
373 /**
374  * Test that tune with unknown program type fails.
375  *
376  * Verifies that:
377  *  - tuneByProgramSelector fails with INVALID_ARGUMENT when unknown program type is passed.
378  */
TEST_P(BroadcastRadioHalTest,TuneFailsForUnknownProgram)379 TEST_P(BroadcastRadioHalTest, TuneFailsForUnknownProgram) {
380     if (skipped) return;
381     ASSERT_TRUE(openTuner());
382 
383     // Program type is 1-based, so 0 will be always invalid.
384     ProgramSelector sel = {};
385     auto tuneResult = mTuner->tuneByProgramSelector(sel);
386     ASSERT_EQ(Result::INVALID_ARGUMENTS, tuneResult);
387 }
388 
389 /**
390  * Test cancelling announcement.
391  *
392  * Verifies that:
393  *  - cancelAnnouncement succeeds either when there is an announcement or there is none.
394  */
TEST_P(BroadcastRadioHalTest,CancelAnnouncement)395 TEST_P(BroadcastRadioHalTest, CancelAnnouncement) {
396     if (skipped) return;
397     ASSERT_TRUE(openTuner());
398 
399     auto hidlResult = mTuner->cancelAnnouncement();
400     EXPECT_EQ(Result::OK, hidlResult);
401 }
402 
403 /**
404  * Test getImage call with invalid image ID.
405  *
406  * Verifies that:
407  * - getImage call handles argument 0 gracefully.
408  */
TEST_P(BroadcastRadioHalTest,GetNoImage)409 TEST_P(BroadcastRadioHalTest, GetNoImage) {
410     if (skipped) return;
411 
412     size_t len = 0;
413     auto hidlResult =
414         mRadioModule->getImage(0, [&](hidl_vec<uint8_t> rawImage) { len = rawImage.size(); });
415 
416     ASSERT_TRUE(hidlResult.isOk());
417     ASSERT_EQ(0u, len);
418 }
419 
420 /**
421  * Test proper image format in metadata.
422  *
423  * Verifies that:
424  * - all images in metadata are provided out-of-band (by id, not as a binary blob);
425  * - images are available for getImage call.
426  */
TEST_P(BroadcastRadioHalTest,OobImagesOnly)427 TEST_P(BroadcastRadioHalTest, OobImagesOnly) {
428     if (skipped) return;
429     ASSERT_TRUE(openTuner());
430 
431     std::vector<int> imageIds;
432 
433     do {
434         auto getCb = [&](const hidl_vec<ProgramInfo>& list) {
435             for (auto&& program : list) {
436                 for (auto&& entry : program.base.metadata) {
437                     EXPECT_NE(MetadataType::RAW, entry.type);
438                     if (entry.key != MetadataKey::ICON && entry.key != MetadataKey::ART) continue;
439                     EXPECT_NE(0, entry.intValue);
440                     EXPECT_EQ(0u, entry.rawValue.size());
441                     if (entry.intValue != 0) imageIds.push_back(entry.intValue);
442                 }
443             }
444         };
445         getProgramList(getCb);
446     } while (nextBand());
447 
448     if (imageIds.size() == 0) {
449         printSkipped("No images found");
450         return;
451     }
452 
453     for (auto id : imageIds) {
454         ALOGD("Checking image %d", id);
455 
456         size_t len = 0;
457         auto hidlResult =
458             mRadioModule->getImage(id, [&](hidl_vec<uint8_t> rawImage) { len = rawImage.size(); });
459 
460         ASSERT_TRUE(hidlResult.isOk());
461         ASSERT_GT(len, 0u);
462     }
463 }
464 
465 /**
466  * Test AnalogForced switch.
467  *
468  * Verifies that:
469  * - setAnalogForced results either with INVALID_STATE, or isAnalogForced replying the same.
470  */
TEST_P(BroadcastRadioHalTest,AnalogForcedSwitch)471 TEST_P(BroadcastRadioHalTest, AnalogForcedSwitch) {
472     if (skipped) return;
473     ASSERT_TRUE(openTuner());
474 
475     bool forced;
476     Result halIsResult;
477     auto isCb = [&](Result result, bool isForced) {
478         halIsResult = result;
479         forced = isForced;
480     };
481 
482     // set analog mode
483     auto setResult = mTuner->setAnalogForced(true);
484     ASSERT_TRUE(setResult.isOk());
485     if (Result::INVALID_STATE == setResult) {
486         // if setter fails, getter should fail too - it means the switch is not supported at all
487         auto isResult = mTuner->isAnalogForced(isCb);
488         ASSERT_TRUE(isResult.isOk());
489         EXPECT_EQ(Result::INVALID_STATE, halIsResult);
490         return;
491     }
492     ASSERT_EQ(Result::OK, setResult);
493 
494     // check, if it's analog
495     auto isResult = mTuner->isAnalogForced(isCb);
496     ASSERT_TRUE(isResult.isOk());
497     EXPECT_EQ(Result::OK, halIsResult);
498     ASSERT_TRUE(forced);
499 
500     // set digital mode
501     setResult = mTuner->setAnalogForced(false);
502     ASSERT_EQ(Result::OK, setResult);
503 
504     // check, if it's digital
505     isResult = mTuner->isAnalogForced(isCb);
506     ASSERT_TRUE(isResult.isOk());
507     EXPECT_EQ(Result::OK, halIsResult);
508     ASSERT_FALSE(forced);
509 }
510 
verifyIdentifier(const ProgramIdentifier & id)511 static void verifyIdentifier(const ProgramIdentifier& id) {
512     EXPECT_NE(id.type, 0u);
513     auto val = id.value;
514 
515     switch (static_cast<IdentifierType>(id.type)) {
516         case IdentifierType::AMFM_FREQUENCY:
517         case IdentifierType::DAB_FREQUENCY:
518         case IdentifierType::DRMO_FREQUENCY:
519             EXPECT_GT(val, 100u) << "Expected f > 100kHz";
520             EXPECT_LT(val, 10000000u) << "Expected f < 10GHz";
521             break;
522         case IdentifierType::RDS_PI:
523             EXPECT_GT(val, 0u);
524             EXPECT_LE(val, 0xFFFFu) << "Expected 16bit id";
525             break;
526         case IdentifierType::HD_STATION_ID_EXT: {
527             auto stationId = val & 0xFFFFFFFF;  // 32bit
528             val >>= 32;
529             auto subchannel = val & 0xF;  // 4bit
530             val >>= 4;
531             auto freq = val & 0x3FFFF;  // 18bit
532             EXPECT_GT(stationId, 0u);
533             EXPECT_LT(subchannel, 8u) << "Expected ch < 8";
534             EXPECT_GT(freq, 100u) << "Expected f > 100kHz";
535             EXPECT_LT(freq, 10000000u) << "Expected f < 10GHz";
536             break;
537         }
538         case IdentifierType::HD_SUBCHANNEL:
539             EXPECT_LT(val, 8u) << "Expected ch < 8";
540             break;
541         case IdentifierType::DAB_SIDECC: {
542             auto sid = val & 0xFFFF;  // 16bit
543             val >>= 16;
544             auto ecc = val & 0xFF;  // 8bit
545             EXPECT_NE(sid, 0u);
546             EXPECT_GE(ecc, 0xA0u) << "Invalid ECC, see ETSI TS 101 756 V2.1.1";
547             EXPECT_LE(ecc, 0xF6u) << "Invalid ECC, see ETSI TS 101 756 V2.1.1";
548             break;
549         }
550         case IdentifierType::DAB_ENSEMBLE:
551             EXPECT_GT(val, 0u);
552             EXPECT_LE(val, 0xFFFFu) << "Expected 16bit id";
553             break;
554         case IdentifierType::DAB_SCID:
555             EXPECT_GT(val, 0xFu) << "Expected 12bit SCId (not 4bit SCIdS)";
556             EXPECT_LE(val, 0xFFFu) << "Expected 12bit id";
557             break;
558         case IdentifierType::DRMO_SERVICE_ID:
559             EXPECT_GT(val, 0u);
560             EXPECT_LE(val, 0xFFFFFFu) << "Expected 24bit id";
561             break;
562         case IdentifierType::DRMO_MODULATION:
563             EXPECT_GE(val, static_cast<uint32_t>(Modulation::AM));
564             EXPECT_LE(val, static_cast<uint32_t>(Modulation::FM));
565             break;
566         case IdentifierType::SXM_SERVICE_ID:
567             EXPECT_GT(val, 0u);
568             EXPECT_LE(val, 0xFFFFFFFFu) << "Expected 32bit id";
569             break;
570         case IdentifierType::SXM_CHANNEL:
571             EXPECT_LT(val, 1000u);
572             break;
573         case IdentifierType::VENDOR_PRIMARY_START:
574         case IdentifierType::VENDOR_PRIMARY_END:
575             // skip
576             break;
577     }
578 }
579 
580 /**
581  * Test ProgramIdentifier format.
582  *
583  * Verifies that:
584  * - values of ProgramIdentifier match their definitions at IdentifierType.
585  */
TEST_P(BroadcastRadioHalTest,VerifyIdentifiersFormat)586 TEST_P(BroadcastRadioHalTest, VerifyIdentifiersFormat) {
587     if (skipped) return;
588     ASSERT_TRUE(openTuner());
589 
590     do {
591         auto getCb = [&](const hidl_vec<ProgramInfo>& list) {
592             for (auto&& program : list) {
593                 verifyIdentifier(program.selector.primaryId);
594                 for (auto&& id : program.selector.secondaryIds) {
595                     verifyIdentifier(id);
596                 }
597             }
598         };
599         getProgramList(getCb);
600     } while (nextBand());
601 }
602 
603 INSTANTIATE_TEST_CASE_P(
604         PerInstance, BroadcastRadioHalTest,
605         testing::Combine(testing::ValuesIn(android::hardware::getAllHalInstanceNames(
606                                  IBroadcastRadioFactory::descriptor)),
607                          ::testing::Values("AM_FM", "SAT", "DT")),
608         android::hardware::PrintInstanceTupleNameToString<>);
609 
610 }  // namespace vts
611 }  // namespace V1_1
612 }  // namespace broadcastradio
613 }  // namespace hardware
614 }  // namespace android
615