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