blob: 42af27657adfc32551788f02d0be5d63970ee95e [file] [log] [blame]
Eric Laurent566fcda2016-11-23 10:36:36 -08001/*
2 * Copyright (C) 2016 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 Ma50d7e272017-02-28 01:46:51 -080018#include <VtsHalHidlTargetBaseTest.h>
Eric Laurent566fcda2016-11-23 10:36:36 -080019#include <android-base/logging.h>
20#include <cutils/native_handle.h>
21#include <cutils/properties.h>
Martijn Coenen02822372016-12-29 14:03:41 +010022#include <hidl/HidlTransportSupport.h>
Eric Laurent566fcda2016-11-23 10:36:36 -080023#include <utils/threads.h>
Eric Laurent566fcda2016-11-23 10:36:36 -080024
25#include <android/hardware/broadcastradio/1.0/IBroadcastRadioFactory.h>
26#include <android/hardware/broadcastradio/1.0/IBroadcastRadio.h>
27#include <android/hardware/broadcastradio/1.0/ITuner.h>
28#include <android/hardware/broadcastradio/1.0/ITunerCallback.h>
29#include <android/hardware/broadcastradio/1.0/types.h>
30
31
32using ::android::sp;
33using ::android::Mutex;
34using ::android::Condition;
Eric Laurent566fcda2016-11-23 10:36:36 -080035using ::android::hardware::Return;
36using ::android::hardware::Status;
37using ::android::hardware::Void;
38using ::android::hardware::broadcastradio::V1_0::IBroadcastRadioFactory;
39using ::android::hardware::broadcastradio::V1_0::IBroadcastRadio;
40using ::android::hardware::broadcastradio::V1_0::ITuner;
41using ::android::hardware::broadcastradio::V1_0::ITunerCallback;
42using ::android::hardware::broadcastradio::V1_0::Result;
43using ::android::hardware::broadcastradio::V1_0::Class;
44using ::android::hardware::broadcastradio::V1_0::Properties;
Tomasz Wasilczyk10877cd2017-03-07 17:04:26 -080045using ::android::hardware::broadcastradio::V1_0::Band;
Eric Laurent566fcda2016-11-23 10:36:36 -080046using ::android::hardware::broadcastradio::V1_0::BandConfig;
47using ::android::hardware::broadcastradio::V1_0::Direction;
48using ::android::hardware::broadcastradio::V1_0::ProgramInfo;
49using ::android::hardware::broadcastradio::V1_0::MetaData;
50
51
Tomasz Wasilczyk213170b2017-02-07 17:38:21 -080052// The main test class for Broadcast Radio HIDL HAL.
Eric Laurent566fcda2016-11-23 10:36:36 -080053
Yuexi Ma50d7e272017-02-28 01:46:51 -080054class BroadcastRadioHidlTest : public ::testing::VtsHalHidlTargetBaseTest {
Eric Laurent566fcda2016-11-23 10:36:36 -080055 protected:
56 virtual void SetUp() override {
Eric Laurent566fcda2016-11-23 10:36:36 -080057 sp<IBroadcastRadioFactory> factory =
Yuexi Ma50d7e272017-02-28 01:46:51 -080058 ::testing::VtsHalHidlTargetBaseTest::getService<IBroadcastRadioFactory>();
Eric Laurent566fcda2016-11-23 10:36:36 -080059 if (factory != 0) {
60 factory->connectModule(Class::AM_FM,
61 [&](Result retval, const ::android::sp<IBroadcastRadio>& result) {
62 if (retval == Result::OK) {
63 mRadio = result;
64 }
65 });
66 }
67 mTunerCallback = new MyCallback(this);
68 ASSERT_NE(nullptr, mRadio.get());
Eric Laurent566fcda2016-11-23 10:36:36 -080069 ASSERT_NE(nullptr, mTunerCallback.get());
70 }
71
72 virtual void TearDown() override {
73 mTuner.clear();
74 mRadio.clear();
75 }
76
77 class MyCallback : public ITunerCallback {
78 public:
79
80 // ITunerCallback methods (see doc in ITunerCallback.hal)
81 virtual Return<void> hardwareFailure() {
82 ALOGI("%s", __FUNCTION__);
83 mParentTest->onHwFailureCallback();
84 return Void();
85 }
86
87 virtual Return<void> configChange(Result result, const BandConfig& config __unused) {
88 ALOGI("%s result %d", __FUNCTION__, result);
89 mParentTest->onResultCallback(result);
90 return Void();
91 }
92
93 virtual Return<void> tuneComplete(Result result, const ProgramInfo& info __unused) {
94 ALOGI("%s result %d", __FUNCTION__, result);
95 mParentTest->onResultCallback(result);
96 return Void();
97 }
98
99 virtual Return<void> afSwitch(const ProgramInfo& info __unused) {
100 return Void();
101 }
102
103 virtual Return<void> antennaStateChange(bool connected) {
104 ALOGI("%s connected %d", __FUNCTION__, connected);
105 return Void();
106 }
107
108 virtual Return<void> trafficAnnouncement(bool active) {
109 ALOGI("%s active %d", __FUNCTION__, active);
110 return Void();
111 }
112
113 virtual Return<void> emergencyAnnouncement(bool active) {
114 ALOGI("%s active %d", __FUNCTION__, active);
115 return Void();
116 }
117
118 virtual Return<void> newMetadata(uint32_t channel __unused, uint32_t subChannel __unused,
119 const ::android::hardware::hidl_vec<MetaData>& metadata __unused) {
120 ALOGI("%s", __FUNCTION__);
121 return Void();
122 }
123
124 MyCallback(BroadcastRadioHidlTest *parentTest) : mParentTest(parentTest) {}
125
126 private:
127 // BroadcastRadioHidlTest instance to which callbacks will be notified.
128 BroadcastRadioHidlTest *mParentTest;
129 };
130
131
132 /**
133 * Method called by MyCallback when a callback with no status or boolean value is received
134 */
135 void onCallback() {
136 Mutex::Autolock _l(mLock);
137 onCallback_l();
138 }
139
140 /**
141 * Method called by MyCallback when hardwareFailure() callback is received
142 */
143 void onHwFailureCallback() {
144 Mutex::Autolock _l(mLock);
145 mHwFailure = true;
146 onCallback_l();
147 }
148
149 /**
150 * Method called by MyCallback when a callback with status is received
151 */
152 void onResultCallback(Result result) {
153 Mutex::Autolock _l(mLock);
154 mResultCallbackData = result;
155 onCallback_l();
156 }
157
158 /**
159 * Method called by MyCallback when a boolean indication is received
160 */
161 void onBoolCallback(bool result) {
162 Mutex::Autolock _l(mLock);
163 mBoolCallbackData = result;
164 onCallback_l();
165 }
166
167
168 BroadcastRadioHidlTest() :
169 mCallbackCalled(false), mBoolCallbackData(false),
170 mResultCallbackData(Result::OK), mHwFailure(false) {}
171
172 void onCallback_l() {
173 if (!mCallbackCalled) {
174 mCallbackCalled = true;
175 mCallbackCond.broadcast();
176 }
177 }
178
179
180 bool waitForCallback(nsecs_t reltime = 0) {
181 Mutex::Autolock _l(mLock);
182 nsecs_t endTime = systemTime() + reltime;
183 while (!mCallbackCalled) {
184 if (reltime == 0) {
185 mCallbackCond.wait(mLock);
186 } else {
187 nsecs_t now = systemTime();
188 if (now > endTime) {
189 return false;
190 }
191 mCallbackCond.waitRelative(mLock, endTime - now);
192 }
193 }
194 return true;
195 }
196
197 bool getProperties();
198 bool openTuner();
199 bool checkAntenna();
200
201 static const nsecs_t kConfigCallbacktimeoutNs = seconds_to_nanoseconds(10);
202 static const nsecs_t kTuneCallbacktimeoutNs = seconds_to_nanoseconds(30);
203
204 sp<IBroadcastRadio> mRadio;
205 Properties mHalProperties;
206 sp<ITuner> mTuner;
207 sp<MyCallback> mTunerCallback;
208 Mutex mLock;
209 Condition mCallbackCond;
210 bool mCallbackCalled;
211 bool mBoolCallbackData;
212 Result mResultCallbackData;
213 bool mHwFailure;
214};
215
216// A class for test environment setup (kept since this file is a template).
217class BroadcastRadioHidlEnvironment : public ::testing::Environment {
218 public:
219 virtual void SetUp() {}
220 virtual void TearDown() {}
221};
222
223bool BroadcastRadioHidlTest::getProperties()
224{
225 if (mHalProperties.bands.size() == 0) {
226 Result halResult = Result::NOT_INITIALIZED;
227 Return<void> hidlReturn =
228 mRadio->getProperties([&](Result result, const Properties& properties) {
229 halResult = result;
230 if (result == Result::OK) {
231 mHalProperties = properties;
232 }
233 });
234
Steven Morelandb6438422017-01-03 17:06:57 -0800235 EXPECT_TRUE(hidlReturn.isOk());
Eric Laurent566fcda2016-11-23 10:36:36 -0800236 EXPECT_EQ(Result::OK, halResult);
237 EXPECT_EQ(Class::AM_FM, mHalProperties.classId);
238 EXPECT_GT(mHalProperties.numTuners, 0u);
239 EXPECT_GT(mHalProperties.bands.size(), 0u);
240 }
241 return mHalProperties.bands.size() > 0;
242}
243
244bool BroadcastRadioHidlTest::openTuner()
245{
246 if (!getProperties()) {
247 return false;
248 }
249 if (mTuner.get() == nullptr) {
250 Result halResult = Result::NOT_INITIALIZED;
251 Return<void> hidlReturn =
252 mRadio->openTuner(mHalProperties.bands[0], true, mTunerCallback,
253 [&](Result result, const sp<ITuner>& tuner) {
254 halResult = result;
255 if (result == Result::OK) {
256 mTuner = tuner;
257 }
258 });
Steven Morelandb6438422017-01-03 17:06:57 -0800259 EXPECT_TRUE(hidlReturn.isOk());
Eric Laurent566fcda2016-11-23 10:36:36 -0800260 EXPECT_EQ(Result::OK, halResult);
261 EXPECT_EQ(true, waitForCallback(kConfigCallbacktimeoutNs));
262 }
263 EXPECT_NE(nullptr, mTuner.get());
264 return nullptr != mTuner.get();
265}
266
267bool BroadcastRadioHidlTest::checkAntenna()
268{
269 BandConfig halConfig;
270 Result halResult = Result::NOT_INITIALIZED;
271 Return<void> hidlReturn =
272 mTuner->getConfiguration([&](Result result, const BandConfig& config) {
273 halResult = result;
274 if (result == Result::OK) {
275 halConfig = config;
276 }
277 });
278
279 return ((halResult == Result::OK) && (halConfig.antennaConnected == true));
280}
281
282
283/**
284 * Test IBroadcastRadio::getProperties() method
285 *
286 * Verifies that:
287 * - the HAL implements the method
288 * - the method returns 0 (no error)
289 * - the implementation class is AM_FM
290 * - the implementation supports at least one tuner
291 * - the implementation supports at one band
292 */
293TEST_F(BroadcastRadioHidlTest, GetProperties) {
294 EXPECT_EQ(true, getProperties());
295}
296
297/**
298 * Test IBroadcastRadio::openTuner() method
299 *
300 * Verifies that:
301 * - the HAL implements the method
302 * - the method returns 0 (no error) and a valid ITuner interface
303 */
304TEST_F(BroadcastRadioHidlTest, OpenTuner) {
305 EXPECT_EQ(true, openTuner());
306}
307
308/**
Tomasz Wasilczykbe71e9c2016-12-22 11:49:17 -0800309 * Test IBroadcastRadio::openTuner() after ITuner disposal.
310 *
311 * Verifies that:
312 * - ITuner destruction gets propagated through HAL
313 * - the openTuner method works well when called for the second time
314 */
315TEST_F(BroadcastRadioHidlTest, ReopenTuner) {
316 EXPECT_TRUE(openTuner());
317 mTuner.clear();
318 EXPECT_TRUE(openTuner());
319}
320
321/**
322 * Test IBroadcastRadio::openTuner() method called twice.
323 *
324 * Verifies that:
325 * - the openTuner method fails when called for the second time without deleting previous
326 * ITuner instance
327 */
328TEST_F(BroadcastRadioHidlTest, OpenTunerTwice) {
329 EXPECT_TRUE(openTuner());
330
331 Result halResult = Result::NOT_INITIALIZED;
332 Return<void> hidlReturn =
333 mRadio->openTuner(mHalProperties.bands[0], true, mTunerCallback,
334 [&](Result result, const sp<ITuner>&) {
335 halResult = result;
336 });
337 EXPECT_TRUE(hidlReturn.isOk());
338 EXPECT_EQ(Result::INVALID_STATE, halResult);
339 EXPECT_TRUE(waitForCallback(kConfigCallbacktimeoutNs));
340}
341
342/**
Eric Laurent566fcda2016-11-23 10:36:36 -0800343 * 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_EQ(true, openTuner());
353 // test setConfiguration
354 mCallbackCalled = false;
355 Return<Result> hidlResult = mTuner->setConfiguration(mHalProperties.bands[0]);
Steven Morelandb6438422017-01-03 17:06:57 -0800356 EXPECT_TRUE(hidlResult.isOk());
Eric Laurent566fcda2016-11-23 10:36:36 -0800357 EXPECT_EQ(Result::OK, hidlResult);
358 EXPECT_EQ(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 });
Steven Morelandb6438422017-01-03 17:06:57 -0800371 EXPECT_TRUE(hidlReturn.isOk());
Eric Laurent566fcda2016-11-23 10:36:36 -0800372 EXPECT_EQ(Result::OK, halResult);
373 EXPECT_EQ(mHalProperties.bands[0].type, halConfig.type);
374}
375
376/**
Tomasz Wasilczyk10877cd2017-03-07 17:04:26 -0800377 * Test ITuner::setConfiguration() with invalid arguments.
378 *
379 * Verifies that:
380 * - the methods returns INVALID_ARGUMENTS on invalid arguments
381 * - the method recovers and succeeds after passing correct arguments
382 */
383TEST_F(BroadcastRadioHidlTest, SetConfigurationFails) {
384 ASSERT_EQ(true, openTuner());
385
386 // Let's define a config that's bad for sure.
387 BandConfig badConfig = {};
388 badConfig.type = Band::FM;
389 badConfig.lowerLimit = 0xFFFFFFFF;
390 badConfig.upperLimit = 0;
391 badConfig.spacings = (std::vector<uint32_t>){ 0 };
392
393 // Test setConfiguration failing on bad data.
394 mCallbackCalled = false;
395 auto setResult = mTuner->setConfiguration(badConfig);
396 EXPECT_TRUE(setResult.isOk());
397 EXPECT_EQ(Result::INVALID_ARGUMENTS, setResult);
398
399 // Test setConfiguration recovering after passing good data.
400 mCallbackCalled = false;
401 setResult = mTuner->setConfiguration(mHalProperties.bands[0]);
402 EXPECT_TRUE(setResult.isOk());
403 EXPECT_EQ(Result::OK, setResult);
404 EXPECT_EQ(true, waitForCallback(kConfigCallbacktimeoutNs));
405 EXPECT_EQ(Result::OK, mResultCallbackData);
406}
407
408/**
Eric Laurent566fcda2016-11-23 10:36:36 -0800409 * Test ITuner::scan
410 *
411 * Verifies that:
412 * - the HAL implements the method
413 * - the method returns 0 (no error)
414 * - the tuned callback is received within kTuneCallbacktimeoutNs ns
415 */
416TEST_F(BroadcastRadioHidlTest, Scan) {
417 ASSERT_EQ(true, openTuner());
418 ASSERT_TRUE(checkAntenna());
419 // test scan UP
420 mCallbackCalled = false;
421 Return<Result> hidlResult = mTuner->scan(Direction::UP, true);
Steven Morelandb6438422017-01-03 17:06:57 -0800422 EXPECT_TRUE(hidlResult.isOk());
Eric Laurent566fcda2016-11-23 10:36:36 -0800423 EXPECT_EQ(Result::OK, hidlResult);
424 EXPECT_EQ(true, waitForCallback(kTuneCallbacktimeoutNs));
425
426 // test scan DOWN
427 mCallbackCalled = false;
428 hidlResult = mTuner->scan(Direction::DOWN, true);
Steven Morelandb6438422017-01-03 17:06:57 -0800429 EXPECT_TRUE(hidlResult.isOk());
Eric Laurent566fcda2016-11-23 10:36:36 -0800430 EXPECT_EQ(Result::OK, hidlResult);
431 EXPECT_EQ(true, waitForCallback(kTuneCallbacktimeoutNs));
432}
433
434/**
435 * Test ITuner::step
436 *
437 * Verifies that:
438 * - the HAL implements the method
439 * - the method returns 0 (no error)
440 * - the tuned callback is received within kTuneCallbacktimeoutNs ns
441 */
442TEST_F(BroadcastRadioHidlTest, Step) {
443 ASSERT_EQ(true, openTuner());
444 ASSERT_TRUE(checkAntenna());
445 // test step UP
446 mCallbackCalled = false;
447 Return<Result> hidlResult = mTuner->step(Direction::UP, true);
Steven Morelandb6438422017-01-03 17:06:57 -0800448 EXPECT_TRUE(hidlResult.isOk());
Eric Laurent566fcda2016-11-23 10:36:36 -0800449 EXPECT_EQ(Result::OK, hidlResult);
450 EXPECT_EQ(true, waitForCallback(kTuneCallbacktimeoutNs));
451
452 // test step DOWN
453 mCallbackCalled = false;
454 hidlResult = mTuner->step(Direction::DOWN, true);
Steven Morelandb6438422017-01-03 17:06:57 -0800455 EXPECT_TRUE(hidlResult.isOk());
Eric Laurent566fcda2016-11-23 10:36:36 -0800456 EXPECT_EQ(Result::OK, hidlResult);
457 EXPECT_EQ(true, waitForCallback(kTuneCallbacktimeoutNs));
458}
459
460/**
461 * Test ITuner::tune, getProgramInformation and cancel methods
462 *
463 * Verifies that:
464 * - the HAL implements the methods
465 * - the methods return 0 (no error)
466 * - the tuned callback is received within kTuneCallbacktimeoutNs ns after tune()
467 */
468TEST_F(BroadcastRadioHidlTest, TuneAndGetProgramInformationAndCancel) {
469 ASSERT_EQ(true, openTuner());
470 ASSERT_TRUE(checkAntenna());
471
472 // test tune
473 ASSERT_GT(mHalProperties.bands[0].spacings.size(), 0u);
474 ASSERT_GT(mHalProperties.bands[0].upperLimit, mHalProperties.bands[0].lowerLimit);
475
476 // test scan UP
477 uint32_t lowerLimit = mHalProperties.bands[0].lowerLimit;
478 uint32_t upperLimit = mHalProperties.bands[0].upperLimit;
479 uint32_t spacing = mHalProperties.bands[0].spacings[0];
480
481 uint32_t channel =
482 lowerLimit + (((upperLimit - lowerLimit) / 2 + spacing - 1) / spacing) * spacing;
483 mCallbackCalled = false;
484 mResultCallbackData = Result::NOT_INITIALIZED;
485 Return<Result> hidlResult = mTuner->tune(channel, 0);
Steven Morelandb6438422017-01-03 17:06:57 -0800486 EXPECT_TRUE(hidlResult.isOk());
Eric Laurent566fcda2016-11-23 10:36:36 -0800487 EXPECT_EQ(Result::OK, hidlResult);
488 EXPECT_EQ(true, waitForCallback(kTuneCallbacktimeoutNs));
489
490 // test getProgramInformation
491 ProgramInfo halInfo;
492 Result halResult = Result::NOT_INITIALIZED;
493 Return<void> hidlReturn = mTuner->getProgramInformation(
Tomasz Wasilczyk5cc9d862017-01-06 14:19:11 -0800494 [&](Result result, const ProgramInfo& info) {
495 halResult = result;
496 if (result == Result::OK) {
497 halInfo = info;
498 }
Eric Laurent566fcda2016-11-23 10:36:36 -0800499 });
Steven Morelandb6438422017-01-03 17:06:57 -0800500 EXPECT_TRUE(hidlReturn.isOk());
Eric Laurent566fcda2016-11-23 10:36:36 -0800501 EXPECT_EQ(Result::OK, halResult);
502 if (mResultCallbackData == Result::OK) {
503 EXPECT_EQ(true, halInfo.tuned);
504 EXPECT_LE(halInfo.channel, upperLimit);
505 EXPECT_GE(halInfo.channel, lowerLimit);
506 } else {
507 EXPECT_EQ(false, halInfo.tuned);
508 }
509
510 // test cancel
511 mTuner->tune(lowerLimit, 0);
512 hidlResult = mTuner->cancel();
Steven Morelandb6438422017-01-03 17:06:57 -0800513 EXPECT_TRUE(hidlResult.isOk());
Eric Laurent566fcda2016-11-23 10:36:36 -0800514 EXPECT_EQ(Result::OK, hidlResult);
515}
516
Tomasz Wasilczyk59d985d2017-03-03 13:02:15 -0800517/**
518 * Test ITuner::tune failing when channel out of the range is provided.
519 *
520 * Verifies that:
521 * - the method returns INVALID_ARGUMENTS when applicable
522 * - the method recovers and succeeds after passing correct arguments
523 */
524TEST_F(BroadcastRadioHidlTest, TuneFailsOutOfBounds) {
525 ASSERT_TRUE(openTuner());
526 ASSERT_TRUE(checkAntenna());
527
528 // get current channel bounds
529 BandConfig halConfig;
530 Result halResult;
531 auto configResult = mTuner->getConfiguration([&](Result result, const BandConfig& config) {
532 halResult = result;
533 halConfig = config;
534 });
535 ASSERT_TRUE(configResult.isOk());
536 ASSERT_EQ(Result::OK, halResult);
537
538 // try to tune slightly above the limit and expect to fail
539 auto badChannel = halConfig.upperLimit + halConfig.spacings[0];
540 auto tuneResult = mTuner->tune(badChannel, 0);
541 EXPECT_TRUE(tuneResult.isOk());
542 EXPECT_EQ(Result::INVALID_ARGUMENTS, tuneResult);
543 EXPECT_TRUE(waitForCallback(kTuneCallbacktimeoutNs));
544
545 // tuning exactly at the limit should succeed
546 auto goodChannel = halConfig.upperLimit;
547 tuneResult = mTuner->tune(goodChannel, 0);
548 EXPECT_TRUE(tuneResult.isOk());
549 EXPECT_EQ(Result::OK, tuneResult);
550 EXPECT_TRUE(waitForCallback(kTuneCallbacktimeoutNs));
551}
552
Eric Laurent566fcda2016-11-23 10:36:36 -0800553
554int main(int argc, char** argv) {
Eric Laurent566fcda2016-11-23 10:36:36 -0800555 ::testing::AddGlobalTestEnvironment(new BroadcastRadioHidlEnvironment);
556 ::testing::InitGoogleTest(&argc, argv);
557 int status = RUN_ALL_TESTS();
558 ALOGI("Test result = %d", status);
559 return status;
560}