blob: 0de6fa5c787a161cca41b023821388f199d09e79 [file] [log] [blame]
Tomasz Wasilczyk213170b2017-02-07 17:38:21 -08001/*
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 "BroadcastRadioHidlHalTest"
Yuexi Maed2bb4e2017-03-10 00:44:45 -080018#include <VtsHalHidlTargetTestBase.h>
Tomasz Wasilczyk213170b2017-02-07 17:38:21 -080019#include <android-base/logging.h>
20#include <cutils/native_handle.h>
21#include <cutils/properties.h>
22#include <hidl/HidlTransportSupport.h>
23#include <utils/threads.h>
24
25#include <android/hardware/broadcastradio/1.1/IBroadcastRadioFactory.h>
26#include <android/hardware/broadcastradio/1.0/IBroadcastRadio.h>
27#include <android/hardware/broadcastradio/1.1/ITuner.h>
28#include <android/hardware/broadcastradio/1.1/ITunerCallback.h>
29#include <android/hardware/broadcastradio/1.1/types.h>
30
31
32namespace V1_0 = ::android::hardware::broadcastradio::V1_0;
33
34using ::android::sp;
35using ::android::Mutex;
36using ::android::Condition;
37using ::android::hardware::Return;
Tomasz Wasilczyk213170b2017-02-07 17:38:21 -080038using ::android::hardware::Void;
39using ::android::hardware::broadcastradio::V1_0::BandConfig;
40using ::android::hardware::broadcastradio::V1_0::Class;
41using ::android::hardware::broadcastradio::V1_0::Direction;
42using ::android::hardware::broadcastradio::V1_0::IBroadcastRadio;
43using ::android::hardware::broadcastradio::V1_0::MetaData;
44using ::android::hardware::broadcastradio::V1_0::Properties;
45using ::android::hardware::broadcastradio::V1_1::IBroadcastRadioFactory;
46using ::android::hardware::broadcastradio::V1_1::ITuner;
47using ::android::hardware::broadcastradio::V1_1::ITunerCallback;
48using ::android::hardware::broadcastradio::V1_1::ProgramInfo;
49using ::android::hardware::broadcastradio::V1_1::Result;
Tomasz Wasilczyk803301a2017-03-13 14:30:15 -070050using ::android::hardware::broadcastradio::V1_1::ProgramListResult;
Tomasz Wasilczyka02b6ef2017-07-05 11:23:30 -070051using ::android::hardware::hidl_vec;
Tomasz Wasilczyk213170b2017-02-07 17:38:21 -080052
53// The main test class for Broadcast Radio HIDL HAL.
54
Yuexi Maed2bb4e2017-03-10 00:44:45 -080055class BroadcastRadioHidlTest : public ::testing::VtsHalHidlTargetTestBase {
Tomasz Wasilczyk213170b2017-02-07 17:38:21 -080056 protected:
57 virtual void SetUp() override {
Yuexi Maed2bb4e2017-03-10 00:44:45 -080058 auto factory = ::testing::VtsHalHidlTargetTestBase::getService<IBroadcastRadioFactory>();
Tomasz Wasilczyk48377552017-06-22 10:45:33 -070059 ASSERT_NE(nullptr, factory.get());
60 Result halResult;
61 factory->connectModule(Class::AM_FM, [&](Result retval, const sp<IBroadcastRadio>& result) {
62 halResult = retval;
63 if (retval == Result::OK) {
64 mRadio = IBroadcastRadio::castFrom(result);
65 }
66 });
67 ASSERT_EQ(Result::OK, halResult);
Tomasz Wasilczyk213170b2017-02-07 17:38:21 -080068 mTunerCallback = new MyCallback(this);
69 ASSERT_NE(nullptr, mRadio.get());
Tomasz Wasilczyk213170b2017-02-07 17:38:21 -080070 ASSERT_NE(nullptr, mTunerCallback.get());
71 }
72
73 virtual void TearDown() override {
74 mTuner.clear();
75 mRadio.clear();
76 }
77
78 class MyCallback : public ITunerCallback {
79 public:
80
81 // ITunerCallback methods (see doc in ITunerCallback.hal)
82 virtual Return<void> hardwareFailure() {
83 ALOGI("%s", __FUNCTION__);
84 mParentTest->onHwFailureCallback();
85 return Void();
86 }
87
88 virtual Return<void> configChange(Result result, const BandConfig& config __unused) {
89 ALOGI("%s result %d", __FUNCTION__, result);
90 mParentTest->onResultCallback(result);
91 return Void();
92 }
93
94 virtual Return<void> tuneComplete(Result result __unused, const V1_0::ProgramInfo& info __unused) {
95 return Void();
96 }
97
98 virtual Return<void> tuneComplete_1_1(Result result, const ProgramInfo& info __unused) {
99 ALOGI("%s result %d", __FUNCTION__, result);
100 mParentTest->onResultCallback(result);
101 return Void();
102 }
103
104 virtual Return<void> afSwitch(const V1_0::ProgramInfo& info __unused) {
105 return Void();
106 }
107
108 virtual Return<void> afSwitch_1_1(const ProgramInfo& info __unused) {
109 return Void();
110 }
111
112 virtual Return<void> antennaStateChange(bool connected) {
113 ALOGI("%s connected %d", __FUNCTION__, connected);
114 return Void();
115 }
116
117 virtual Return<void> trafficAnnouncement(bool active) {
118 ALOGI("%s active %d", __FUNCTION__, active);
119 return Void();
120 }
121
122 virtual Return<void> emergencyAnnouncement(bool active) {
123 ALOGI("%s active %d", __FUNCTION__, active);
124 return Void();
125 }
126
127 virtual Return<void> newMetadata(uint32_t channel __unused, uint32_t subChannel __unused,
128 const ::android::hardware::hidl_vec<MetaData>& metadata __unused) {
129 ALOGI("%s", __FUNCTION__);
130 return Void();
131 }
132
Tomasz Wasilczyk22e5f172017-03-27 15:18:58 -0700133 virtual Return<void> backgroundScanAvailable(bool isAvailable __unused) {
134 return Void();
135 }
136
Tomasz Wasilczyka02b6ef2017-07-05 11:23:30 -0700137 virtual Return<void> backgroundScanComplete(ProgramListResult result) {
138 ALOGV("%s", __func__);
139 mParentTest->onProgramListResultCallback(result);
Tomasz Wasilczyk803301a2017-03-13 14:30:15 -0700140 return Void();
141 }
142
143 virtual Return<void> programListChanged() {
144 return Void();
145 }
146
Tomasz Wasilczyk213170b2017-02-07 17:38:21 -0800147 MyCallback(BroadcastRadioHidlTest *parentTest) : mParentTest(parentTest) {}
148
149 private:
150 // BroadcastRadioHidlTest instance to which callbacks will be notified.
151 BroadcastRadioHidlTest *mParentTest;
152 };
153
154
155 /**
156 * Method called by MyCallback when a callback with no status or boolean value is received
157 */
158 void onCallback() {
159 Mutex::Autolock _l(mLock);
160 onCallback_l();
161 }
162
163 /**
164 * Method called by MyCallback when hardwareFailure() callback is received
165 */
166 void onHwFailureCallback() {
167 Mutex::Autolock _l(mLock);
168 mHwFailure = true;
169 onCallback_l();
170 }
171
172 /**
173 * Method called by MyCallback when a callback with status is received
174 */
175 void onResultCallback(Result result) {
176 Mutex::Autolock _l(mLock);
177 mResultCallbackData = result;
178 onCallback_l();
179 }
180
181 /**
Tomasz Wasilczyka02b6ef2017-07-05 11:23:30 -0700182 * Method called by MyCallback when a callback with status is received
183 */
184 void onProgramListResultCallback(ProgramListResult result) {
185 Mutex::Autolock _l(mLock);
186 mProgramListResultCallbackData = result;
187 onCallback_l();
188 }
189
190 /**
Tomasz Wasilczyk213170b2017-02-07 17:38:21 -0800191 * Method called by MyCallback when a boolean indication is received
192 */
193 void onBoolCallback(bool result) {
194 Mutex::Autolock _l(mLock);
195 mBoolCallbackData = result;
196 onCallback_l();
197 }
198
199
200 BroadcastRadioHidlTest() :
201 mCallbackCalled(false), mBoolCallbackData(false),
202 mResultCallbackData(Result::OK), mHwFailure(false) {}
203
204 void onCallback_l() {
205 if (!mCallbackCalled) {
206 mCallbackCalled = true;
207 mCallbackCond.broadcast();
208 }
209 }
210
211
212 bool waitForCallback(nsecs_t reltime = 0) {
213 Mutex::Autolock _l(mLock);
214 nsecs_t endTime = systemTime() + reltime;
215 while (!mCallbackCalled) {
216 if (reltime == 0) {
217 mCallbackCond.wait(mLock);
218 } else {
219 nsecs_t now = systemTime();
220 if (now > endTime) {
221 return false;
222 }
223 mCallbackCond.waitRelative(mLock, endTime - now);
224 }
225 }
226 return true;
227 }
228
229 bool getProperties();
230 bool openTuner();
231 bool checkAntenna();
232
233 static const nsecs_t kConfigCallbacktimeoutNs = seconds_to_nanoseconds(10);
234 static const nsecs_t kTuneCallbacktimeoutNs = seconds_to_nanoseconds(30);
Tomasz Wasilczyka02b6ef2017-07-05 11:23:30 -0700235 static const nsecs_t kFullScanTimeoutNs = seconds_to_nanoseconds(60);
Tomasz Wasilczyk213170b2017-02-07 17:38:21 -0800236
237 sp<IBroadcastRadio> mRadio;
238 Properties mHalProperties;
239 sp<ITuner> mTuner;
240 sp<MyCallback> mTunerCallback;
241 Mutex mLock;
242 Condition mCallbackCond;
243 bool mCallbackCalled;
244 bool mBoolCallbackData;
245 Result mResultCallbackData;
Tomasz Wasilczyka02b6ef2017-07-05 11:23:30 -0700246 ProgramListResult mProgramListResultCallbackData;
Tomasz Wasilczyk213170b2017-02-07 17:38:21 -0800247 bool mHwFailure;
248};
249
250// A class for test environment setup (kept since this file is a template).
251class BroadcastRadioHidlEnvironment : public ::testing::Environment {
252 public:
253 virtual void SetUp() {}
254 virtual void TearDown() {}
255};
256
257bool BroadcastRadioHidlTest::getProperties()
258{
259 if (mHalProperties.bands.size() == 0) {
260 Result halResult = Result::NOT_INITIALIZED;
261 Return<void> hidlReturn =
262 mRadio->getProperties([&](Result result, const Properties& properties) {
263 halResult = result;
264 if (result == Result::OK) {
265 mHalProperties = properties;
266 }
267 });
268
269 EXPECT_TRUE(hidlReturn.isOk());
270 EXPECT_EQ(Result::OK, halResult);
271 EXPECT_EQ(Class::AM_FM, mHalProperties.classId);
272 EXPECT_GT(mHalProperties.numTuners, 0u);
273 EXPECT_GT(mHalProperties.bands.size(), 0u);
274 }
275 return mHalProperties.bands.size() > 0;
276}
277
278bool BroadcastRadioHidlTest::openTuner()
279{
280 if (!getProperties()) {
281 return false;
282 }
283 if (mTuner.get() == nullptr) {
284 Result halResult = Result::NOT_INITIALIZED;
285 auto hidlReturn = mRadio->openTuner(mHalProperties.bands[0], true, mTunerCallback,
286 [&](Result result, const sp<V1_0::ITuner>& tuner) {
287 halResult = result;
288 if (result == Result::OK) {
289 mTuner = ITuner::castFrom(tuner);
290 }
291 });
292 EXPECT_TRUE(hidlReturn.isOk());
293 EXPECT_EQ(Result::OK, halResult);
Tomasz Wasilczyk48377552017-06-22 10:45:33 -0700294 EXPECT_NE(nullptr, mTuner.get());
Tomasz Wasilczyk213170b2017-02-07 17:38:21 -0800295 EXPECT_TRUE(waitForCallback(kConfigCallbacktimeoutNs));
296 }
297 EXPECT_NE(nullptr, mTuner.get());
298 return nullptr != mTuner.get();
299}
300
301bool BroadcastRadioHidlTest::checkAntenna()
302{
303 BandConfig halConfig;
304 Result halResult = Result::NOT_INITIALIZED;
305 Return<void> hidlReturn =
306 mTuner->getConfiguration([&](Result result, const BandConfig& config) {
307 halResult = result;
308 if (result == Result::OK) {
309 halConfig = config;
310 }
311 });
312
313 return ((halResult == Result::OK) && (halConfig.antennaConnected == true));
314}
315
316
317/**
318 * Test IBroadcastRadio::getProperties() method
319 *
320 * Verifies that:
321 * - the HAL implements the method
322 * - the method returns 0 (no error)
323 * - the implementation class is AM_FM
324 * - the implementation supports at least one tuner
325 * - the implementation supports at one band
326 */
327TEST_F(BroadcastRadioHidlTest, GetProperties) {
328 EXPECT_TRUE(getProperties());
329}
330
331/**
332 * Test IBroadcastRadio::openTuner() method
333 *
334 * Verifies that:
335 * - the HAL implements the method
336 * - the method returns 0 (no error) and a valid ITuner interface
337 */
338TEST_F(BroadcastRadioHidlTest, OpenTuner) {
339 EXPECT_TRUE(openTuner());
340}
341
342/**
343 * Test ITuner::setConfiguration() and getConfiguration methods
344 *
345 * Verifies that:
346 * - the HAL implements both methods
347 * - the methods return 0 (no error)
348 * - the configuration callback is received within kConfigCallbacktimeoutNs ns
349 * - the configuration read back from HAl has the same class Id
350 */
351TEST_F(BroadcastRadioHidlTest, SetAndGetConfiguration) {
352 ASSERT_TRUE(openTuner());
353 // test setConfiguration
354 mCallbackCalled = false;
355 Return<Result> hidlResult = mTuner->setConfiguration(mHalProperties.bands[0]);
356 EXPECT_TRUE(hidlResult.isOk());
357 EXPECT_EQ(Result::OK, hidlResult);
358 EXPECT_TRUE(waitForCallback(kConfigCallbacktimeoutNs));
359 EXPECT_EQ(Result::OK, mResultCallbackData);
360
361 // test getConfiguration
362 BandConfig halConfig;
363 Result halResult;
364 Return<void> hidlReturn =
365 mTuner->getConfiguration([&](Result result, const BandConfig& config) {
366 halResult = result;
367 if (result == Result::OK) {
368 halConfig = config;
369 }
370 });
371 EXPECT_TRUE(hidlReturn.isOk());
372 EXPECT_EQ(Result::OK, halResult);
373 EXPECT_EQ(mHalProperties.bands[0].type, halConfig.type);
374}
375
376/**
377 * Test ITuner::scan
378 *
379 * Verifies that:
380 * - the HAL implements the method
381 * - the method returns 0 (no error)
382 * - the tuned callback is received within kTuneCallbacktimeoutNs ns
383 */
384TEST_F(BroadcastRadioHidlTest, Scan) {
385 ASSERT_TRUE(openTuner());
386 ASSERT_TRUE(checkAntenna());
387 // test scan UP
388 mCallbackCalled = false;
389 Return<Result> hidlResult = mTuner->scan(Direction::UP, true);
390 EXPECT_TRUE(hidlResult.isOk());
391 EXPECT_EQ(Result::OK, hidlResult);
392 EXPECT_TRUE(waitForCallback(kTuneCallbacktimeoutNs));
393
394 // test scan DOWN
395 mCallbackCalled = false;
396 hidlResult = mTuner->scan(Direction::DOWN, true);
397 EXPECT_TRUE(hidlResult.isOk());
398 EXPECT_EQ(Result::OK, hidlResult);
399 EXPECT_TRUE(waitForCallback(kTuneCallbacktimeoutNs));
400}
401
402/**
403 * Test ITuner::step
404 *
405 * Verifies that:
406 * - the HAL implements the method
407 * - the method returns 0 (no error)
408 * - the tuned callback is received within kTuneCallbacktimeoutNs ns
409 */
410TEST_F(BroadcastRadioHidlTest, Step) {
411 ASSERT_TRUE(openTuner());
412 ASSERT_TRUE(checkAntenna());
413 // test step UP
414 mCallbackCalled = false;
415 Return<Result> hidlResult = mTuner->step(Direction::UP, true);
416 EXPECT_TRUE(hidlResult.isOk());
417 EXPECT_EQ(Result::OK, hidlResult);
418 EXPECT_TRUE(waitForCallback(kTuneCallbacktimeoutNs));
419
420 // test step DOWN
421 mCallbackCalled = false;
422 hidlResult = mTuner->step(Direction::DOWN, true);
423 EXPECT_TRUE(hidlResult.isOk());
424 EXPECT_EQ(Result::OK, hidlResult);
425 EXPECT_TRUE(waitForCallback(kTuneCallbacktimeoutNs));
426}
427
428/**
429 * Test ITuner::tune, getProgramInformation and cancel methods
430 *
431 * Verifies that:
432 * - the HAL implements the methods
433 * - the methods return 0 (no error)
434 * - the tuned callback is received within kTuneCallbacktimeoutNs ns after tune()
435 */
436TEST_F(BroadcastRadioHidlTest, TuneAndGetProgramInformationAndCancel) {
437 ASSERT_TRUE(openTuner());
438 ASSERT_TRUE(checkAntenna());
439
440 // test tune
441 ASSERT_GT(mHalProperties.bands[0].spacings.size(), 0u);
442 ASSERT_GT(mHalProperties.bands[0].upperLimit, mHalProperties.bands[0].lowerLimit);
443
444 // test scan UP
445 uint32_t lowerLimit = mHalProperties.bands[0].lowerLimit;
446 uint32_t upperLimit = mHalProperties.bands[0].upperLimit;
447 uint32_t spacing = mHalProperties.bands[0].spacings[0];
448
449 uint32_t channel =
450 lowerLimit + (((upperLimit - lowerLimit) / 2 + spacing - 1) / spacing) * spacing;
451 mCallbackCalled = false;
452 mResultCallbackData = Result::NOT_INITIALIZED;
453 Return<Result> hidlResult = mTuner->tune(channel, 0);
454 EXPECT_TRUE(hidlResult.isOk());
455 EXPECT_EQ(Result::OK, hidlResult);
456 EXPECT_TRUE(waitForCallback(kTuneCallbacktimeoutNs));
457
458 // test getProgramInformation
459 ProgramInfo halInfo;
460 Result halResult = Result::NOT_INITIALIZED;
461 Return<void> hidlReturn = mTuner->getProgramInformation_1_1(
462 [&](Result result, const ProgramInfo& info) {
463 halResult = result;
464 if (result == Result::OK) {
465 halInfo = info;
466 }
467 });
468 EXPECT_TRUE(hidlReturn.isOk());
469 EXPECT_EQ(Result::OK, halResult);
470 auto &halInfo_1_1 = halInfo.base;
471 if (mResultCallbackData == Result::OK) {
Tomasz Wasilczyk213170b2017-02-07 17:38:21 -0800472 EXPECT_LE(halInfo_1_1.channel, upperLimit);
473 EXPECT_GE(halInfo_1_1.channel, lowerLimit);
Tomasz Wasilczyk213170b2017-02-07 17:38:21 -0800474 }
475
476 // test cancel
477 mTuner->tune(lowerLimit, 0);
478 hidlResult = mTuner->cancel();
479 EXPECT_TRUE(hidlResult.isOk());
480 EXPECT_EQ(Result::OK, hidlResult);
481}
482
Tomasz Wasilczyka02b6ef2017-07-05 11:23:30 -0700483TEST_F(BroadcastRadioHidlTest, TuneFromProgramList) {
484 ASSERT_TRUE(openTuner());
485 ASSERT_TRUE(checkAntenna());
486
487 ProgramInfo firstProgram;
488 bool isListEmpty;
489 ProgramListResult getListResult = ProgramListResult::NOT_INITIALIZED;
490 auto getListCb = [&](ProgramListResult result, const hidl_vec<ProgramInfo>& list) {
491 getListResult = result;
492 if (result != ProgramListResult::OK) return;
493 isListEmpty = (list.size() == 0);
494 // don't copy the whole list out, it might be heavy
495 if (!isListEmpty) firstProgram = list[0];
496 };
497
498 // first try...
499 auto hidlReturn = mTuner->getProgramList("", getListCb);
500 ASSERT_TRUE(hidlReturn.isOk());
501
502 if (getListResult == ProgramListResult::NOT_STARTED) {
503 auto result = mTuner->startBackgroundScan();
504 ASSERT_TRUE(result.isOk());
505 ASSERT_EQ(ProgramListResult::OK, result);
506 getListResult = ProgramListResult::NOT_READY; // continue as in NOT_READY case
507 }
508 if (getListResult == ProgramListResult::NOT_READY) {
509 ASSERT_TRUE(waitForCallback(kFullScanTimeoutNs));
510 ASSERT_EQ(ProgramListResult::OK, mProgramListResultCallbackData);
511
512 // second (last) try...
513 hidlReturn = mTuner->getProgramList("", getListCb);
514 ASSERT_TRUE(hidlReturn.isOk());
515 ASSERT_EQ(ProgramListResult::OK, getListResult);
516 }
517
518 if (isListEmpty) {
519 std::cout << "[ SKIPPED ] Program list is empty. " << std::endl;
520 return;
521 }
522
523 auto tuneResult = mTuner->tune_1_1(firstProgram.selector);
524 ASSERT_TRUE(tuneResult.isOk());
525 EXPECT_EQ(Result::OK, tuneResult);
526 EXPECT_EQ(true, waitForCallback(kTuneCallbacktimeoutNs));
527 // TODO(b/36864490): check this too, when mProgramInfoCallbackData is cherry-picked from 1.0
528 // EXPECT_EQ(firstProgram.selector.primaryId, mProgramInfoCallbackData.selector.primaryId);
529}
Tomasz Wasilczyk213170b2017-02-07 17:38:21 -0800530
531int main(int argc, char** argv) {
532 ::testing::AddGlobalTestEnvironment(new BroadcastRadioHidlEnvironment);
533 ::testing::InitGoogleTest(&argc, argv);
534 int status = RUN_ALL_TESTS();
535 ALOGI("Test result = %d", status);
536 return status;
537}