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