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