blob: 0204191c658983fa01a830ede367500b5741e00b [file] [log] [blame]
Tomasz Wasilczykd921f612017-10-03 07:26:11 -07001/*
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 "broadcastradio.vts"
18
19#include <VtsHalHidlTargetTestBase.h>
20#include <android/hardware/broadcastradio/1.1/IBroadcastRadio.h>
21#include <android/hardware/broadcastradio/1.2/IBroadcastRadioFactory.h>
22#include <android/hardware/broadcastradio/1.2/ITuner.h>
23#include <android/hardware/broadcastradio/1.2/ITunerCallback.h>
24#include <android/hardware/broadcastradio/1.2/types.h>
25#include <android-base/logging.h>
Tomasz Wasilczykd921f612017-10-03 07:26:11 -070026#include <broadcastradio-vts-utils/call-barrier.h>
27#include <broadcastradio-vts-utils/mock-timeout.h>
28#include <cutils/native_handle.h>
29#include <cutils/properties.h>
30#include <gmock/gmock.h>
31#include <hidl/HidlTransportSupport.h>
32#include <utils/threads.h>
33
34#include <chrono>
35
36namespace android {
37namespace hardware {
38namespace broadcastradio {
39namespace V1_2 {
40namespace vts {
41
42using namespace std::chrono_literals;
43
44using testing::_;
45using testing::AnyNumber;
46using testing::ByMove;
47using testing::DoAll;
48using testing::Invoke;
49using testing::SaveArg;
50
51using broadcastradio::vts::CallBarrier;
52using V1_0::BandConfig;
53using V1_0::Class;
54using V1_0::MetaData;
55using V1_0::MetadataKey;
56using V1_0::MetadataType;
57using V1_1::IBroadcastRadio;
58using V1_1::ProgramInfo;
59using V1_1::ProgramListResult;
60using V1_1::ProgramSelector;
61using V1_1::Properties;
62
63using std::chrono::steady_clock;
64using std::this_thread::sleep_for;
65
66static constexpr auto kConfigTimeout = 10s;
67static constexpr auto kConnectModuleTimeout = 1s;
68
69static void printSkipped(std::string msg) {
70 std::cout << "[ SKIPPED ] " << msg << std::endl;
71}
72
73struct TunerCallbackMock : public ITunerCallback {
74 TunerCallbackMock() { EXPECT_CALL(*this, hardwareFailure()).Times(0); }
75
76 MOCK_METHOD0(hardwareFailure, Return<void>());
77 MOCK_TIMEOUT_METHOD2(configChange, Return<void>(Result, const BandConfig&));
78 MOCK_METHOD2(tuneComplete, Return<void>(Result, const V1_0::ProgramInfo&));
79 MOCK_TIMEOUT_METHOD2(tuneComplete_1_1, Return<void>(Result, const ProgramSelector&));
80 MOCK_METHOD1(afSwitch, Return<void>(const V1_0::ProgramInfo&));
81 MOCK_METHOD1(antennaStateChange, Return<void>(bool connected));
82 MOCK_METHOD1(trafficAnnouncement, Return<void>(bool active));
83 MOCK_METHOD1(emergencyAnnouncement, Return<void>(bool active));
84 MOCK_METHOD3(newMetadata, Return<void>(uint32_t ch, uint32_t subCh, const hidl_vec<MetaData>&));
85 MOCK_METHOD1(backgroundScanAvailable, Return<void>(bool));
86 MOCK_TIMEOUT_METHOD1(backgroundScanComplete, Return<void>(ProgramListResult));
87 MOCK_METHOD0(programListChanged, Return<void>());
88 MOCK_TIMEOUT_METHOD1(currentProgramInfoChanged, Return<void>(const ProgramInfo&));
89 MOCK_METHOD1(parametersUpdated, Return<void>(const hidl_vec<VendorKeyValue>& parameters));
90};
91
92class BroadcastRadioHalTest : public ::testing::VtsHalHidlTargetTestBase,
93 public ::testing::WithParamInterface<Class> {
94 protected:
95 virtual void SetUp() override;
96 virtual void TearDown() override;
97
98 bool openTuner();
99
100 Class radioClass;
101 bool skipped = false;
102
103 sp<IBroadcastRadio> mRadioModule;
104 sp<ITuner> mTuner;
105 sp<TunerCallbackMock> mCallback = new TunerCallbackMock();
106
107 private:
108 const BandConfig& getBand(unsigned idx);
109
110 hidl_vec<BandConfig> mBands;
111};
112
113/**
114 * Clears strong pointer and waits until the object gets destroyed.
115 *
116 * @param ptr The pointer to get cleared.
117 * @param timeout Time to wait for other references.
118 */
119template <typename T>
120static void clearAndWait(sp<T>& ptr, std::chrono::milliseconds timeout) {
121 wp<T> wptr = ptr;
122 ptr.clear();
123 auto limit = steady_clock::now() + timeout;
124 while (wptr.promote() != nullptr) {
125 constexpr auto step = 10ms;
126 if (steady_clock::now() + step > limit) {
127 FAIL() << "Pointer was not released within timeout";
128 break;
129 }
130 sleep_for(step);
131 }
132}
133
134void BroadcastRadioHalTest::SetUp() {
135 radioClass = GetParam();
136
137 // lookup HIDL service
138 auto factory = getService<IBroadcastRadioFactory>();
139 ASSERT_NE(nullptr, factory.get());
140
141 // connect radio module
142 Result connectResult;
143 CallBarrier onConnect;
144 factory->connectModule(radioClass, [&](Result ret, const sp<V1_0::IBroadcastRadio>& radio) {
145 connectResult = ret;
146 if (ret == Result::OK) mRadioModule = IBroadcastRadio::castFrom(radio);
147 onConnect.call();
148 });
149 ASSERT_TRUE(onConnect.waitForCall(kConnectModuleTimeout));
150
151 if (connectResult == Result::INVALID_ARGUMENTS) {
152 printSkipped("This device class is not supported.");
153 skipped = true;
154 return;
155 }
156 ASSERT_EQ(connectResult, Result::OK);
157 ASSERT_NE(nullptr, mRadioModule.get());
158
159 // get module properties
160 Properties prop11;
161 auto& prop10 = prop11.base;
162 auto propResult =
163 mRadioModule->getProperties_1_1([&](const Properties& properties) { prop11 = properties; });
164
165 ASSERT_TRUE(propResult.isOk());
166 EXPECT_EQ(radioClass, prop10.classId);
167 EXPECT_GT(prop10.numTuners, 0u);
168 EXPECT_GT(prop11.supportedProgramTypes.size(), 0u);
169 EXPECT_GT(prop11.supportedIdentifierTypes.size(), 0u);
170 if (radioClass == Class::AM_FM) {
171 EXPECT_GT(prop10.bands.size(), 0u);
172 }
173 mBands = prop10.bands;
174}
175
176void BroadcastRadioHalTest::TearDown() {
177 mTuner.clear();
178 mRadioModule.clear();
179 clearAndWait(mCallback, 1s);
180}
181
182bool BroadcastRadioHalTest::openTuner() {
183 EXPECT_EQ(nullptr, mTuner.get());
184
185 if (radioClass == Class::AM_FM) {
186 EXPECT_TIMEOUT_CALL(*mCallback, configChange, Result::OK, _);
187 }
188
189 Result halResult = Result::NOT_INITIALIZED;
190 auto openCb = [&](Result result, const sp<V1_0::ITuner>& tuner) {
191 halResult = result;
192 if (result != Result::OK) return;
193 mTuner = ITuner::castFrom(tuner);
194 };
195 auto hidlResult = mRadioModule->openTuner(getBand(0), true, mCallback, openCb);
196
197 EXPECT_TRUE(hidlResult.isOk());
198 EXPECT_EQ(Result::OK, halResult);
199 EXPECT_NE(nullptr, mTuner.get());
200 if (radioClass == Class::AM_FM && mTuner != nullptr) {
201 EXPECT_TIMEOUT_CALL_WAIT(*mCallback, configChange, kConfigTimeout);
202
203 BandConfig halConfig;
204 Result halResult = Result::NOT_INITIALIZED;
205 mTuner->getConfiguration([&](Result result, const BandConfig& config) {
206 halResult = result;
207 halConfig = config;
208 });
209 EXPECT_EQ(Result::OK, halResult);
210 EXPECT_TRUE(halConfig.antennaConnected);
211 }
212
213 EXPECT_NE(nullptr, mTuner.get());
214 return nullptr != mTuner.get();
215}
216
217const BandConfig& BroadcastRadioHalTest::getBand(unsigned idx) {
218 static const BandConfig dummyBandConfig = {};
219
220 if (radioClass != Class::AM_FM) {
221 ALOGD("Not AM/FM radio, returning dummy band config");
222 return dummyBandConfig;
223 }
224
225 EXPECT_GT(mBands.size(), idx);
226 if (mBands.size() <= idx) {
227 ALOGD("Band index out of bound, returning dummy band config");
228 return dummyBandConfig;
229 }
230
231 auto& band = mBands[idx];
232 ALOGD("Returning %s band", toString(band.type).c_str());
233 return band;
234}
235
236/**
237 * Test IBroadcastRadio::get|setParameters() methods called with no parameters.
238 *
239 * Verifies that:
240 * - callback is called for empty parameters set.
241 */
242TEST_P(BroadcastRadioHalTest, NoParameters) {
243 if (skipped) return;
244
245 ASSERT_TRUE(openTuner());
246
247 hidl_vec<VendorKeyValue> halResults = {};
248 bool wasCalled = false;
249 auto cb = [&](hidl_vec<VendorKeyValue> results) {
250 wasCalled = true;
251 halResults = results;
252 };
253
254 auto hidlResult = mTuner->setParameters({}, cb);
255 ASSERT_TRUE(hidlResult.isOk());
256 ASSERT_TRUE(wasCalled);
257 ASSERT_EQ(0u, halResults.size());
258
259 wasCalled = false;
260 hidlResult = mTuner->getParameters({}, cb);
261 ASSERT_TRUE(hidlResult.isOk());
262 ASSERT_TRUE(wasCalled);
263 ASSERT_EQ(0u, halResults.size());
264}
265
266/**
267 * Test IBroadcastRadio::get|setParameters() methods called with unknown parameters.
268 *
269 * Verifies that:
270 * - unknown parameters are ignored;
271 * - callback is called also for empty results set.
272 */
273TEST_P(BroadcastRadioHalTest, UnknownParameters) {
274 if (skipped) return;
275
276 ASSERT_TRUE(openTuner());
277
278 hidl_vec<VendorKeyValue> halResults = {};
279 bool wasCalled = false;
280 auto cb = [&](hidl_vec<VendorKeyValue> results) {
281 wasCalled = true;
282 halResults = results;
283 };
284
285 auto hidlResult = mTuner->setParameters({{"com.google.unknown", "dummy"}}, cb);
286 ASSERT_TRUE(hidlResult.isOk());
287 ASSERT_TRUE(wasCalled);
288 ASSERT_EQ(0u, halResults.size());
289
290 wasCalled = false;
291 hidlResult = mTuner->getParameters({{"com.google.unknown*", "dummy"}}, cb);
292 ASSERT_TRUE(hidlResult.isOk());
293 ASSERT_TRUE(wasCalled);
294 ASSERT_EQ(0u, halResults.size());
295}
296
Tomasz Wasilczyk002151c2017-11-22 09:43:06 -0800297// TODO(b/69860743): implement VerifyIdentifiersFormat test when
298// the new program list fetching mechanism is implemented
299
Tomasz Wasilczykd921f612017-10-03 07:26:11 -0700300INSTANTIATE_TEST_CASE_P(BroadcastRadioHalTestCases, BroadcastRadioHalTest,
301 ::testing::Values(Class::AM_FM, Class::SAT, Class::DT));
302
303} // namespace vts
304} // namespace V1_2
305} // namespace broadcastradio
306} // namespace hardware
307} // namespace android
308
309int main(int argc, char** argv) {
310 ::testing::InitGoogleTest(&argc, argv);
311 int status = RUN_ALL_TESTS();
312 ALOGI("Test result = %d", status);
313 return status;
314}