blob: b980d3193807c0266291407430c59f0015894b82 [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 Ma50d7e272017-02-28 01:46:51 -080018#include <VtsHalHidlTargetBaseTest.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;
38using ::android::hardware::Status;
39using ::android::hardware::Void;
40using ::android::hardware::broadcastradio::V1_0::BandConfig;
41using ::android::hardware::broadcastradio::V1_0::Class;
42using ::android::hardware::broadcastradio::V1_0::Direction;
43using ::android::hardware::broadcastradio::V1_0::IBroadcastRadio;
44using ::android::hardware::broadcastradio::V1_0::MetaData;
45using ::android::hardware::broadcastradio::V1_0::Properties;
46using ::android::hardware::broadcastradio::V1_1::IBroadcastRadioFactory;
47using ::android::hardware::broadcastradio::V1_1::ITuner;
48using ::android::hardware::broadcastradio::V1_1::ITunerCallback;
49using ::android::hardware::broadcastradio::V1_1::ProgramInfo;
50using ::android::hardware::broadcastradio::V1_1::Result;
51
52
53// The main test class for Broadcast Radio HIDL HAL.
54
Yuexi Ma50d7e272017-02-28 01:46:51 -080055class BroadcastRadioHidlTest : public ::testing::VtsHalHidlTargetBaseTest {
Tomasz Wasilczyk213170b2017-02-07 17:38:21 -080056 protected:
57 virtual void SetUp() override {
Yuexi Ma50d7e272017-02-28 01:46:51 -080058 auto factory = ::testing::VtsHalHidlTargetBaseTest::getService<IBroadcastRadioFactory>();
Tomasz Wasilczyk213170b2017-02-07 17:38:21 -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 = IBroadcastRadio::castFrom(result);
64 }
65 });
66 }
67 mTunerCallback = new MyCallback(this);
68 ASSERT_NE(nullptr, mRadio.get());
Tomasz Wasilczyk213170b2017-02-07 17:38:21 -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 __unused, const V1_0::ProgramInfo& info __unused) {
94 return Void();
95 }
96
97 virtual Return<void> tuneComplete_1_1(Result result, const ProgramInfo& info __unused) {
98 ALOGI("%s result %d", __FUNCTION__, result);
99 mParentTest->onResultCallback(result);
100 return Void();
101 }
102
103 virtual Return<void> afSwitch(const V1_0::ProgramInfo& info __unused) {
104 return Void();
105 }
106
107 virtual Return<void> afSwitch_1_1(const ProgramInfo& info __unused) {
108 return Void();
109 }
110
111 virtual Return<void> antennaStateChange(bool connected) {
112 ALOGI("%s connected %d", __FUNCTION__, connected);
113 return Void();
114 }
115
116 virtual Return<void> trafficAnnouncement(bool active) {
117 ALOGI("%s active %d", __FUNCTION__, active);
118 return Void();
119 }
120
121 virtual Return<void> emergencyAnnouncement(bool active) {
122 ALOGI("%s active %d", __FUNCTION__, active);
123 return Void();
124 }
125
126 virtual Return<void> newMetadata(uint32_t channel __unused, uint32_t subChannel __unused,
127 const ::android::hardware::hidl_vec<MetaData>& metadata __unused) {
128 ALOGI("%s", __FUNCTION__);
129 return Void();
130 }
131
132 MyCallback(BroadcastRadioHidlTest *parentTest) : mParentTest(parentTest) {}
133
134 private:
135 // BroadcastRadioHidlTest instance to which callbacks will be notified.
136 BroadcastRadioHidlTest *mParentTest;
137 };
138
139
140 /**
141 * Method called by MyCallback when a callback with no status or boolean value is received
142 */
143 void onCallback() {
144 Mutex::Autolock _l(mLock);
145 onCallback_l();
146 }
147
148 /**
149 * Method called by MyCallback when hardwareFailure() callback is received
150 */
151 void onHwFailureCallback() {
152 Mutex::Autolock _l(mLock);
153 mHwFailure = true;
154 onCallback_l();
155 }
156
157 /**
158 * Method called by MyCallback when a callback with status is received
159 */
160 void onResultCallback(Result result) {
161 Mutex::Autolock _l(mLock);
162 mResultCallbackData = result;
163 onCallback_l();
164 }
165
166 /**
167 * Method called by MyCallback when a boolean indication is received
168 */
169 void onBoolCallback(bool result) {
170 Mutex::Autolock _l(mLock);
171 mBoolCallbackData = result;
172 onCallback_l();
173 }
174
175
176 BroadcastRadioHidlTest() :
177 mCallbackCalled(false), mBoolCallbackData(false),
178 mResultCallbackData(Result::OK), mHwFailure(false) {}
179
180 void onCallback_l() {
181 if (!mCallbackCalled) {
182 mCallbackCalled = true;
183 mCallbackCond.broadcast();
184 }
185 }
186
187
188 bool waitForCallback(nsecs_t reltime = 0) {
189 Mutex::Autolock _l(mLock);
190 nsecs_t endTime = systemTime() + reltime;
191 while (!mCallbackCalled) {
192 if (reltime == 0) {
193 mCallbackCond.wait(mLock);
194 } else {
195 nsecs_t now = systemTime();
196 if (now > endTime) {
197 return false;
198 }
199 mCallbackCond.waitRelative(mLock, endTime - now);
200 }
201 }
202 return true;
203 }
204
205 bool getProperties();
206 bool openTuner();
207 bool checkAntenna();
208
209 static const nsecs_t kConfigCallbacktimeoutNs = seconds_to_nanoseconds(10);
210 static const nsecs_t kTuneCallbacktimeoutNs = seconds_to_nanoseconds(30);
211
212 sp<IBroadcastRadio> mRadio;
213 Properties mHalProperties;
214 sp<ITuner> mTuner;
215 sp<MyCallback> mTunerCallback;
216 Mutex mLock;
217 Condition mCallbackCond;
218 bool mCallbackCalled;
219 bool mBoolCallbackData;
220 Result mResultCallbackData;
221 bool mHwFailure;
222};
223
224// A class for test environment setup (kept since this file is a template).
225class BroadcastRadioHidlEnvironment : public ::testing::Environment {
226 public:
227 virtual void SetUp() {}
228 virtual void TearDown() {}
229};
230
231bool BroadcastRadioHidlTest::getProperties()
232{
233 if (mHalProperties.bands.size() == 0) {
234 Result halResult = Result::NOT_INITIALIZED;
235 Return<void> hidlReturn =
236 mRadio->getProperties([&](Result result, const Properties& properties) {
237 halResult = result;
238 if (result == Result::OK) {
239 mHalProperties = properties;
240 }
241 });
242
243 EXPECT_TRUE(hidlReturn.isOk());
244 EXPECT_EQ(Result::OK, halResult);
245 EXPECT_EQ(Class::AM_FM, mHalProperties.classId);
246 EXPECT_GT(mHalProperties.numTuners, 0u);
247 EXPECT_GT(mHalProperties.bands.size(), 0u);
248 }
249 return mHalProperties.bands.size() > 0;
250}
251
252bool BroadcastRadioHidlTest::openTuner()
253{
254 if (!getProperties()) {
255 return false;
256 }
257 if (mTuner.get() == nullptr) {
258 Result halResult = Result::NOT_INITIALIZED;
259 auto hidlReturn = mRadio->openTuner(mHalProperties.bands[0], true, mTunerCallback,
260 [&](Result result, const sp<V1_0::ITuner>& tuner) {
261 halResult = result;
262 if (result == Result::OK) {
263 mTuner = ITuner::castFrom(tuner);
264 }
265 });
266 EXPECT_TRUE(hidlReturn.isOk());
267 EXPECT_EQ(Result::OK, halResult);
268 EXPECT_TRUE(waitForCallback(kConfigCallbacktimeoutNs));
269 }
270 EXPECT_NE(nullptr, mTuner.get());
271 return nullptr != mTuner.get();
272}
273
274bool BroadcastRadioHidlTest::checkAntenna()
275{
276 BandConfig halConfig;
277 Result halResult = Result::NOT_INITIALIZED;
278 Return<void> hidlReturn =
279 mTuner->getConfiguration([&](Result result, const BandConfig& config) {
280 halResult = result;
281 if (result == Result::OK) {
282 halConfig = config;
283 }
284 });
285
286 return ((halResult == Result::OK) && (halConfig.antennaConnected == true));
287}
288
289
290/**
291 * Test IBroadcastRadio::getProperties() method
292 *
293 * Verifies that:
294 * - the HAL implements the method
295 * - the method returns 0 (no error)
296 * - the implementation class is AM_FM
297 * - the implementation supports at least one tuner
298 * - the implementation supports at one band
299 */
300TEST_F(BroadcastRadioHidlTest, GetProperties) {
301 EXPECT_TRUE(getProperties());
302}
303
304/**
305 * Test IBroadcastRadio::openTuner() method
306 *
307 * Verifies that:
308 * - the HAL implements the method
309 * - the method returns 0 (no error) and a valid ITuner interface
310 */
311TEST_F(BroadcastRadioHidlTest, OpenTuner) {
312 EXPECT_TRUE(openTuner());
313}
314
315/**
316 * Test ITuner::setConfiguration() and getConfiguration methods
317 *
318 * Verifies that:
319 * - the HAL implements both methods
320 * - the methods return 0 (no error)
321 * - the configuration callback is received within kConfigCallbacktimeoutNs ns
322 * - the configuration read back from HAl has the same class Id
323 */
324TEST_F(BroadcastRadioHidlTest, SetAndGetConfiguration) {
325 ASSERT_TRUE(openTuner());
326 // test setConfiguration
327 mCallbackCalled = false;
328 Return<Result> hidlResult = mTuner->setConfiguration(mHalProperties.bands[0]);
329 EXPECT_TRUE(hidlResult.isOk());
330 EXPECT_EQ(Result::OK, hidlResult);
331 EXPECT_TRUE(waitForCallback(kConfigCallbacktimeoutNs));
332 EXPECT_EQ(Result::OK, mResultCallbackData);
333
334 // test getConfiguration
335 BandConfig halConfig;
336 Result halResult;
337 Return<void> hidlReturn =
338 mTuner->getConfiguration([&](Result result, const BandConfig& config) {
339 halResult = result;
340 if (result == Result::OK) {
341 halConfig = config;
342 }
343 });
344 EXPECT_TRUE(hidlReturn.isOk());
345 EXPECT_EQ(Result::OK, halResult);
346 EXPECT_EQ(mHalProperties.bands[0].type, halConfig.type);
347}
348
349/**
350 * Test ITuner::scan
351 *
352 * Verifies that:
353 * - the HAL implements the method
354 * - the method returns 0 (no error)
355 * - the tuned callback is received within kTuneCallbacktimeoutNs ns
356 */
357TEST_F(BroadcastRadioHidlTest, Scan) {
358 ASSERT_TRUE(openTuner());
359 ASSERT_TRUE(checkAntenna());
360 // test scan UP
361 mCallbackCalled = false;
362 Return<Result> hidlResult = mTuner->scan(Direction::UP, true);
363 EXPECT_TRUE(hidlResult.isOk());
364 EXPECT_EQ(Result::OK, hidlResult);
365 EXPECT_TRUE(waitForCallback(kTuneCallbacktimeoutNs));
366
367 // test scan DOWN
368 mCallbackCalled = false;
369 hidlResult = mTuner->scan(Direction::DOWN, true);
370 EXPECT_TRUE(hidlResult.isOk());
371 EXPECT_EQ(Result::OK, hidlResult);
372 EXPECT_TRUE(waitForCallback(kTuneCallbacktimeoutNs));
373}
374
375/**
376 * Test ITuner::step
377 *
378 * Verifies that:
379 * - the HAL implements the method
380 * - the method returns 0 (no error)
381 * - the tuned callback is received within kTuneCallbacktimeoutNs ns
382 */
383TEST_F(BroadcastRadioHidlTest, Step) {
384 ASSERT_TRUE(openTuner());
385 ASSERT_TRUE(checkAntenna());
386 // test step UP
387 mCallbackCalled = false;
388 Return<Result> hidlResult = mTuner->step(Direction::UP, true);
389 EXPECT_TRUE(hidlResult.isOk());
390 EXPECT_EQ(Result::OK, hidlResult);
391 EXPECT_TRUE(waitForCallback(kTuneCallbacktimeoutNs));
392
393 // test step DOWN
394 mCallbackCalled = false;
395 hidlResult = mTuner->step(Direction::DOWN, true);
396 EXPECT_TRUE(hidlResult.isOk());
397 EXPECT_EQ(Result::OK, hidlResult);
398 EXPECT_TRUE(waitForCallback(kTuneCallbacktimeoutNs));
399}
400
401/**
402 * Test ITuner::tune, getProgramInformation and cancel methods
403 *
404 * Verifies that:
405 * - the HAL implements the methods
406 * - the methods return 0 (no error)
407 * - the tuned callback is received within kTuneCallbacktimeoutNs ns after tune()
408 */
409TEST_F(BroadcastRadioHidlTest, TuneAndGetProgramInformationAndCancel) {
410 ASSERT_TRUE(openTuner());
411 ASSERT_TRUE(checkAntenna());
412
413 // test tune
414 ASSERT_GT(mHalProperties.bands[0].spacings.size(), 0u);
415 ASSERT_GT(mHalProperties.bands[0].upperLimit, mHalProperties.bands[0].lowerLimit);
416
417 // test scan UP
418 uint32_t lowerLimit = mHalProperties.bands[0].lowerLimit;
419 uint32_t upperLimit = mHalProperties.bands[0].upperLimit;
420 uint32_t spacing = mHalProperties.bands[0].spacings[0];
421
422 uint32_t channel =
423 lowerLimit + (((upperLimit - lowerLimit) / 2 + spacing - 1) / spacing) * spacing;
424 mCallbackCalled = false;
425 mResultCallbackData = Result::NOT_INITIALIZED;
426 Return<Result> hidlResult = mTuner->tune(channel, 0);
427 EXPECT_TRUE(hidlResult.isOk());
428 EXPECT_EQ(Result::OK, hidlResult);
429 EXPECT_TRUE(waitForCallback(kTuneCallbacktimeoutNs));
430
431 // test getProgramInformation
432 ProgramInfo halInfo;
433 Result halResult = Result::NOT_INITIALIZED;
434 Return<void> hidlReturn = mTuner->getProgramInformation_1_1(
435 [&](Result result, const ProgramInfo& info) {
436 halResult = result;
437 if (result == Result::OK) {
438 halInfo = info;
439 }
440 });
441 EXPECT_TRUE(hidlReturn.isOk());
442 EXPECT_EQ(Result::OK, halResult);
443 auto &halInfo_1_1 = halInfo.base;
444 if (mResultCallbackData == Result::OK) {
445 EXPECT_TRUE(halInfo_1_1.tuned);
446 EXPECT_LE(halInfo_1_1.channel, upperLimit);
447 EXPECT_GE(halInfo_1_1.channel, lowerLimit);
448 } else {
449 EXPECT_EQ(false, halInfo_1_1.tuned);
450 }
451
452 // test cancel
453 mTuner->tune(lowerLimit, 0);
454 hidlResult = mTuner->cancel();
455 EXPECT_TRUE(hidlResult.isOk());
456 EXPECT_EQ(Result::OK, hidlResult);
457}
458
459
460int main(int argc, char** argv) {
461 ::testing::AddGlobalTestEnvironment(new BroadcastRadioHidlEnvironment);
462 ::testing::InitGoogleTest(&argc, argv);
463 int status = RUN_ALL_TESTS();
464 ALOGI("Test result = %d", status);
465 return status;
466}