blob: 6910d95cd384ad899e3bdb88e8a5642c98252c36 [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
Tomasz Wasilczykc9ba6462017-07-07 13:28:00 -070017#define LOG_TAG "broadcastradio.vts"
18
Yuexi Maed2bb4e2017-03-10 00:44:45 -080019#include <VtsHalHidlTargetTestBase.h>
Tomasz Wasilczyk213170b2017-02-07 17:38:21 -080020#include <android-base/logging.h>
Tomasz Wasilczykc9ba6462017-07-07 13:28:00 -070021#include <call-barrier.h>
Tomasz Wasilczyk213170b2017-02-07 17:38:21 -080022#include <cutils/native_handle.h>
23#include <cutils/properties.h>
Tomasz Wasilczykc9ba6462017-07-07 13:28:00 -070024#include <gmock/gmock.h>
Tomasz Wasilczyk213170b2017-02-07 17:38:21 -080025#include <hidl/HidlTransportSupport.h>
26#include <utils/threads.h>
27
Tomasz Wasilczykc9ba6462017-07-07 13:28:00 -070028#include <chrono>
29
30#include <android/hardware/broadcastradio/1.1/IBroadcastRadio.h>
Tomasz Wasilczyk213170b2017-02-07 17:38:21 -080031#include <android/hardware/broadcastradio/1.1/IBroadcastRadioFactory.h>
Tomasz Wasilczyk213170b2017-02-07 17:38:21 -080032#include <android/hardware/broadcastradio/1.1/ITuner.h>
33#include <android/hardware/broadcastradio/1.1/ITunerCallback.h>
34#include <android/hardware/broadcastradio/1.1/types.h>
35
Tomasz Wasilczykc9ba6462017-07-07 13:28:00 -070036#include "mock-timeout.h"
Tomasz Wasilczyk213170b2017-02-07 17:38:21 -080037
Tomasz Wasilczykc9ba6462017-07-07 13:28:00 -070038namespace android {
39namespace hardware {
40namespace broadcastradio {
41namespace V1_1 {
42namespace vts {
Tomasz Wasilczyk213170b2017-02-07 17:38:21 -080043
Tomasz Wasilczykc9ba6462017-07-07 13:28:00 -070044using namespace std::chrono_literals;
Tomasz Wasilczyk213170b2017-02-07 17:38:21 -080045
Tomasz Wasilczykc9ba6462017-07-07 13:28:00 -070046using testing::_;
47using testing::AnyNumber;
48using testing::ByMove;
49using testing::DoAll;
Tomasz Wasilczyk24180092017-07-14 10:44:52 -070050using testing::Invoke;
Tomasz Wasilczykc9ba6462017-07-07 13:28:00 -070051using testing::SaveArg;
Tomasz Wasilczyk213170b2017-02-07 17:38:21 -080052
Tomasz Wasilczykc9ba6462017-07-07 13:28:00 -070053using broadcastradio::vts::CallBarrier;
54using V1_0::BandConfig;
55using V1_0::Class;
56using V1_0::MetaData;
Tomasz Wasilczyk213170b2017-02-07 17:38:21 -080057
Tomasz Wasilczykc9ba6462017-07-07 13:28:00 -070058static constexpr auto kConfigTimeout = 10s;
59static constexpr auto kConnectModuleTimeout = 1s;
60static constexpr auto kTuneTimeout = 30s;
61static constexpr auto kFullScanTimeout = 1min;
Tomasz Wasilczyk213170b2017-02-07 17:38:21 -080062
Tomasz Wasilczykc9ba6462017-07-07 13:28:00 -070063static void printSkipped(std::string msg) {
64 std::cout << "[ SKIPPED ] " << msg << std::endl;
Tomasz Wasilczyk213170b2017-02-07 17:38:21 -080065}
66
Tomasz Wasilczyk24180092017-07-14 10:44:52 -070067struct TunerCallbackMock : public ITunerCallback {
68 TunerCallbackMock() { EXPECT_CALL(*this, hardwareFailure()).Times(0); }
69
Tomasz Wasilczykc9ba6462017-07-07 13:28:00 -070070 MOCK_METHOD0(hardwareFailure, Return<void>());
71 MOCK_TIMEOUT_METHOD2(configChange, Return<void>(Result, const BandConfig&));
72 MOCK_METHOD2(tuneComplete, Return<void>(Result, const V1_0::ProgramInfo&));
Tomasz Wasilczykf8866e72017-07-13 15:51:21 -070073 MOCK_TIMEOUT_METHOD2(tuneComplete_1_1, Return<void>(Result, const ProgramSelector&));
Tomasz Wasilczykc9ba6462017-07-07 13:28:00 -070074 MOCK_METHOD1(afSwitch, Return<void>(const V1_0::ProgramInfo&));
Tomasz Wasilczykf8866e72017-07-13 15:51:21 -070075 MOCK_METHOD1(afSwitch_1_1, Return<void>(const ProgramSelector&));
Tomasz Wasilczykc9ba6462017-07-07 13:28:00 -070076 MOCK_METHOD1(antennaStateChange, Return<void>(bool connected));
77 MOCK_METHOD1(trafficAnnouncement, Return<void>(bool active));
78 MOCK_METHOD1(emergencyAnnouncement, Return<void>(bool active));
79 MOCK_METHOD3(newMetadata, Return<void>(uint32_t ch, uint32_t subCh, const hidl_vec<MetaData>&));
80 MOCK_METHOD1(backgroundScanAvailable, Return<void>(bool));
81 MOCK_TIMEOUT_METHOD1(backgroundScanComplete, Return<void>(ProgramListResult));
82 MOCK_METHOD0(programListChanged, Return<void>());
Tomasz Wasilczykf8866e72017-07-13 15:51:21 -070083 MOCK_METHOD0(programInfoChanged, Return<void>());
Tomasz Wasilczykc9ba6462017-07-07 13:28:00 -070084};
85
86class BroadcastRadioHalTest : public ::testing::VtsHalHidlTargetTestBase,
87 public ::testing::WithParamInterface<Class> {
88 protected:
89 virtual void SetUp() override;
90 virtual void TearDown() override;
91
92 // TODO(b/36864490): check all bands for good test conditions (ie. FM is more likely to have
93 // any stations on the list, so don't pick AM blindly).
94 bool openTuner(unsigned band);
95 const BandConfig& getBand(unsigned idx);
96
97 Class radioClass;
98 bool skipped = false;
99
100 sp<IBroadcastRadio> mRadioModule;
101 sp<ITuner> mTuner;
102 sp<TunerCallbackMock> mCallback = new TunerCallbackMock();
103
104 private:
105 hidl_vec<BandConfig> mBands;
106};
107
108void BroadcastRadioHalTest::SetUp() {
109 radioClass = GetParam();
110
Tomasz Wasilczykc9ba6462017-07-07 13:28:00 -0700111 // lookup HIDL service
112 auto factory = getService<IBroadcastRadioFactory>();
113 ASSERT_NE(nullptr, factory.get());
114
115 // connect radio module
116 Result connectResult;
117 CallBarrier onConnect;
118 factory->connectModule(radioClass, [&](Result ret, const sp<V1_0::IBroadcastRadio>& radio) {
119 connectResult = ret;
120 if (ret == Result::OK) mRadioModule = IBroadcastRadio::castFrom(radio);
121 onConnect.call();
122 });
123 ASSERT_TRUE(onConnect.waitForCall(kConnectModuleTimeout));
124
125 if (connectResult == Result::INVALID_ARGUMENTS) {
126 printSkipped("This device class is not supported.");
127 skipped = true;
128 return;
Tomasz Wasilczyk213170b2017-02-07 17:38:21 -0800129 }
Tomasz Wasilczykc9ba6462017-07-07 13:28:00 -0700130 ASSERT_EQ(connectResult, Result::OK);
131 ASSERT_NE(nullptr, mRadioModule.get());
132
133 // get module properties
134 Properties prop11;
135 auto& prop10 = prop11.base;
136 auto propResult =
137 mRadioModule->getProperties_1_1([&](const Properties& properties) { prop11 = properties; });
138
139 ASSERT_TRUE(propResult.isOk());
140 EXPECT_EQ(radioClass, prop10.classId);
141 EXPECT_GT(prop10.numTuners, 0u);
142 if (radioClass == Class::AM_FM) {
143 EXPECT_GT(prop10.bands.size(), 0u);
144 }
145 mBands = prop10.bands;
146}
147
148void BroadcastRadioHalTest::TearDown() {
149 mTuner.clear();
150 mRadioModule.clear();
151 // TODO(b/36864490): wait (with timeout) until mCallback has only one reference
152}
153
154bool BroadcastRadioHalTest::openTuner(unsigned band) {
155 EXPECT_EQ(nullptr, mTuner.get());
156
157 if (radioClass == Class::AM_FM) {
158 EXPECT_TIMEOUT_CALL(*mCallback, configChange, Result::OK, _);
159 }
160
161 Result halResult = Result::NOT_INITIALIZED;
162 auto openCb = [&](Result result, const sp<V1_0::ITuner>& tuner) {
163 halResult = result;
164 if (result != Result::OK) return;
165 mTuner = ITuner::castFrom(tuner);
166 };
167 auto hidlResult = mRadioModule->openTuner(getBand(band), true, mCallback, openCb);
168
169 EXPECT_TRUE(hidlResult.isOk());
170 EXPECT_EQ(Result::OK, halResult);
171 EXPECT_NE(nullptr, mTuner.get());
172 if (radioClass == Class::AM_FM && mTuner != nullptr) {
173 EXPECT_TIMEOUT_CALL_WAIT(*mCallback, configChange, kConfigTimeout);
174
175 BandConfig halConfig;
Tomasz Wasilczyk213170b2017-02-07 17:38:21 -0800176 Result halResult = Result::NOT_INITIALIZED;
Tomasz Wasilczykc9ba6462017-07-07 13:28:00 -0700177 mTuner->getConfiguration([&](Result result, const BandConfig& config) {
178 halResult = result;
179 halConfig = config;
180 });
Tomasz Wasilczyk213170b2017-02-07 17:38:21 -0800181 EXPECT_EQ(Result::OK, halResult);
Tomasz Wasilczykc9ba6462017-07-07 13:28:00 -0700182 EXPECT_TRUE(halConfig.antennaConnected);
Tomasz Wasilczyk213170b2017-02-07 17:38:21 -0800183 }
Tomasz Wasilczykc9ba6462017-07-07 13:28:00 -0700184
Tomasz Wasilczyk213170b2017-02-07 17:38:21 -0800185 EXPECT_NE(nullptr, mTuner.get());
186 return nullptr != mTuner.get();
187}
188
Tomasz Wasilczykc9ba6462017-07-07 13:28:00 -0700189const BandConfig& BroadcastRadioHalTest::getBand(unsigned idx) {
190 static const BandConfig dummyBandConfig = {};
Tomasz Wasilczyk213170b2017-02-07 17:38:21 -0800191
Tomasz Wasilczykc9ba6462017-07-07 13:28:00 -0700192 if (radioClass != Class::AM_FM) {
193 ALOGD("Not AM/FM radio, returning dummy band config");
194 return dummyBandConfig;
Tomasz Wasilczyk213170b2017-02-07 17:38:21 -0800195 }
196
Tomasz Wasilczykc9ba6462017-07-07 13:28:00 -0700197 EXPECT_GT(mBands.size(), idx);
198 if (mBands.size() <= idx) {
199 ALOGD("Band index out of bound, returning dummy band config");
200 return dummyBandConfig;
201 }
202
203 auto& band = mBands[idx];
204 ALOGD("Returning %s band", toString(band.type).c_str());
205 return band;
Tomasz Wasilczyk213170b2017-02-07 17:38:21 -0800206}
207
Tomasz Wasilczykc9ba6462017-07-07 13:28:00 -0700208/**
209 * Test IBroadcastRadio::openTuner() method called twice.
210 *
211 * Verifies that:
212 * - the openTuner method succeeds when called for the second time without
213 * deleting previous ITuner instance.
214 *
215 * This is a more strict requirement than in 1.0, where a second openTuner
216 * might fail.
217 */
218TEST_P(BroadcastRadioHalTest, OpenTunerTwice) {
219 if (skipped) return;
220 ASSERT_TRUE(openTuner(0));
221
222 Result halResult = Result::NOT_INITIALIZED;
223 auto openCb = [&](Result result, const sp<V1_0::ITuner>&) { halResult = result; };
224 auto hidlResult = mRadioModule->openTuner(getBand(0), true, mCallback, openCb);
225 ASSERT_TRUE(hidlResult.isOk());
226 ASSERT_EQ(Result::OK, halResult);
227}
228
229/**
230 * Test tuning to program list entry.
231 *
232 * Verifies that:
233 * - getProgramList either succeeds or returns NOT_STARTED/NOT_READY status;
234 * - if the program list is NOT_STARTED, startBackgroundScan makes it completed
235 * within a full scan timeout and the next getProgramList call succeeds;
236 * - if the program list is not empty, tune_1_1 call succeeds.
237 */
238TEST_P(BroadcastRadioHalTest, TuneFromProgramList) {
239 if (skipped) return;
240 ASSERT_TRUE(openTuner(0));
Tomasz Wasilczyka02b6ef2017-07-05 11:23:30 -0700241
242 ProgramInfo firstProgram;
243 bool isListEmpty;
244 ProgramListResult getListResult = ProgramListResult::NOT_INITIALIZED;
245 auto getListCb = [&](ProgramListResult result, const hidl_vec<ProgramInfo>& list) {
Tomasz Wasilczykc9ba6462017-07-07 13:28:00 -0700246 ALOGD("getListCb(%s, ProgramInfo[%zu])", toString(result).c_str(), list.size());
Tomasz Wasilczyka02b6ef2017-07-05 11:23:30 -0700247 getListResult = result;
248 if (result != ProgramListResult::OK) return;
249 isListEmpty = (list.size() == 0);
250 // don't copy the whole list out, it might be heavy
251 if (!isListEmpty) firstProgram = list[0];
252 };
253
254 // first try...
Tomasz Wasilczykc9ba6462017-07-07 13:28:00 -0700255 EXPECT_TIMEOUT_CALL(*mCallback, backgroundScanComplete, ProgramListResult::OK)
256 .Times(AnyNumber());
257 auto hidlResult = mTuner->getProgramList("", getListCb);
258 ASSERT_TRUE(hidlResult.isOk());
Tomasz Wasilczyka02b6ef2017-07-05 11:23:30 -0700259
260 if (getListResult == ProgramListResult::NOT_STARTED) {
261 auto result = mTuner->startBackgroundScan();
Tomasz Wasilczyka02b6ef2017-07-05 11:23:30 -0700262 ASSERT_EQ(ProgramListResult::OK, result);
263 getListResult = ProgramListResult::NOT_READY; // continue as in NOT_READY case
264 }
265 if (getListResult == ProgramListResult::NOT_READY) {
Tomasz Wasilczykc9ba6462017-07-07 13:28:00 -0700266 EXPECT_TIMEOUT_CALL_WAIT(*mCallback, backgroundScanComplete, kFullScanTimeout);
Tomasz Wasilczyka02b6ef2017-07-05 11:23:30 -0700267
268 // second (last) try...
Tomasz Wasilczykc9ba6462017-07-07 13:28:00 -0700269 hidlResult = mTuner->getProgramList("", getListCb);
270 ASSERT_TRUE(hidlResult.isOk());
Tomasz Wasilczyka02b6ef2017-07-05 11:23:30 -0700271 ASSERT_EQ(ProgramListResult::OK, getListResult);
272 }
273
274 if (isListEmpty) {
Tomasz Wasilczykc9ba6462017-07-07 13:28:00 -0700275 printSkipped("Program list is empty.");
Tomasz Wasilczyka02b6ef2017-07-05 11:23:30 -0700276 return;
277 }
278
Tomasz Wasilczykf8866e72017-07-13 15:51:21 -0700279 ProgramSelector selCb;
Tomasz Wasilczykc9ba6462017-07-07 13:28:00 -0700280 EXPECT_CALL(*mCallback, tuneComplete(_, _));
281 EXPECT_TIMEOUT_CALL(*mCallback, tuneComplete_1_1, Result::OK, _)
Tomasz Wasilczykf8866e72017-07-13 15:51:21 -0700282 .WillOnce(DoAll(SaveArg<1>(&selCb), testing::Return(ByMove(Void()))));
Tomasz Wasilczyka02b6ef2017-07-05 11:23:30 -0700283 auto tuneResult = mTuner->tune_1_1(firstProgram.selector);
Tomasz Wasilczykc9ba6462017-07-07 13:28:00 -0700284 ASSERT_EQ(Result::OK, tuneResult);
285 EXPECT_TIMEOUT_CALL_WAIT(*mCallback, tuneComplete_1_1, kTuneTimeout);
Tomasz Wasilczykf8866e72017-07-13 15:51:21 -0700286 EXPECT_EQ(firstProgram.selector.primaryId, selCb.primaryId);
Tomasz Wasilczyka02b6ef2017-07-05 11:23:30 -0700287}
Tomasz Wasilczyk213170b2017-02-07 17:38:21 -0800288
Tomasz Wasilczyk24180092017-07-14 10:44:52 -0700289TEST_P(BroadcastRadioHalTest, CancelAnnouncement) {
290 if (skipped) return;
291 ASSERT_TRUE(openTuner(0));
292
293 auto hidlResult = mTuner->cancelAnnouncement();
294 EXPECT_EQ(Result::OK, hidlResult);
295}
296
Tomasz Wasilczykc9ba6462017-07-07 13:28:00 -0700297INSTANTIATE_TEST_CASE_P(BroadcastRadioHalTestCases, BroadcastRadioHalTest,
298 ::testing::Values(Class::AM_FM, Class::SAT, Class::DT));
299
300} // namespace vts
301} // namespace V1_1
302} // namespace broadcastradio
303} // namespace hardware
304} // namespace android
305
Tomasz Wasilczyk213170b2017-02-07 17:38:21 -0800306int main(int argc, char** argv) {
Tomasz Wasilczyk213170b2017-02-07 17:38:21 -0800307 ::testing::InitGoogleTest(&argc, argv);
308 int status = RUN_ALL_TESTS();
309 ALOGI("Test result = %d", status);
310 return status;
311}