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