1 /*
2 * Copyright (C) 2018 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 "SoundTriggerHidlHalTest"
18 #include <stdlib.h>
19 #include <time.h>
20
21 #include <condition_variable>
22 #include <mutex>
23
24 #include <android/log.h>
25 #include <cutils/native_handle.h>
26 #include <gtest/gtest.h>
27 #include <hidl/GtestPrinter.h>
28 #include <hidl/ServiceManagement.h>
29 #include <log/log.h>
30
31 #include <android/hardware/audio/common/2.0/types.h>
32 #include <android/hardware/soundtrigger/2.0/ISoundTriggerHw.h>
33 #include <android/hardware/soundtrigger/2.0/types.h>
34 #include <android/hardware/soundtrigger/2.1/ISoundTriggerHw.h>
35 #include <android/hidl/allocator/1.0/IAllocator.h>
36 #include <hidlmemory/mapping.h>
37
38 #define SHORT_TIMEOUT_PERIOD (1)
39
40 using ::android::sp;
41 using ::android::hardware::hidl_memory;
42 using ::android::hardware::hidl_string;
43 using ::android::hardware::hidl_vec;
44 using ::android::hardware::Return;
45 using ::android::hardware::Void;
46 using ::android::hardware::audio::common::V2_0::AudioDevice;
47 using ::android::hardware::soundtrigger::V2_0::PhraseRecognitionExtra;
48 using ::android::hardware::soundtrigger::V2_0::RecognitionMode;
49 using ::android::hardware::soundtrigger::V2_0::SoundModelHandle;
50 using ::android::hardware::soundtrigger::V2_0::SoundModelType;
51 using V2_0_ISoundTriggerHw = ::android::hardware::soundtrigger::V2_0::ISoundTriggerHw;
52 using V2_0_ISoundTriggerHwCallback =
53 ::android::hardware::soundtrigger::V2_0::ISoundTriggerHwCallback;
54 using ::android::hardware::soundtrigger::V2_1::ISoundTriggerHw;
55 using ::android::hardware::soundtrigger::V2_1::ISoundTriggerHwCallback;
56 using ::android::hidl::allocator::V1_0::IAllocator;
57 using ::android::hidl::memory::V1_0::IMemory;
58
59 /**
60 * Test code uses this class to wait for notification from callback.
61 */
62 class Monitor {
63 public:
Monitor()64 Monitor() : mCount(0) {}
65
66 /**
67 * Adds 1 to the internal counter and unblocks one of the waiting threads.
68 */
notify()69 void notify() {
70 std::unique_lock<std::mutex> lock(mMtx);
71 mCount++;
72 mCv.notify_one();
73 }
74
75 /**
76 * Blocks until the internal counter becomes greater than 0.
77 *
78 * If notified, this method decreases the counter by 1 and returns true.
79 * If timeout, returns false.
80 */
wait(int timeoutSeconds)81 bool wait(int timeoutSeconds) {
82 auto deadline = std::chrono::system_clock::now() + std::chrono::seconds(timeoutSeconds);
83 std::unique_lock<std::mutex> lock(mMtx);
84 if (!mCv.wait_until(lock, deadline, [& count = mCount] { return count > 0; })) {
85 return false;
86 }
87 mCount--;
88 return true;
89 }
90
91 private:
92 std::mutex mMtx;
93 std::condition_variable mCv;
94 int mCount;
95 };
96
97 // The main test class for Sound Trigger HIDL HAL.
98 class SoundTriggerHidlTest : public ::testing::TestWithParam<std::string> {
99 public:
SetUp()100 virtual void SetUp() override {
101 mSoundTriggerHal = ISoundTriggerHw::getService(GetParam());
102 ASSERT_NE(nullptr, mSoundTriggerHal.get());
103 mCallback = new SoundTriggerHwCallback(*this);
104 ASSERT_NE(nullptr, mCallback.get());
105 }
106
SetUpTestCase()107 static void SetUpTestCase() { srand(1234); }
108
109 class SoundTriggerHwCallback : public ISoundTriggerHwCallback {
110 private:
111 SoundTriggerHidlTest& mParent;
112
113 public:
SoundTriggerHwCallback(SoundTriggerHidlTest & parent)114 SoundTriggerHwCallback(SoundTriggerHidlTest& parent) : mParent(parent) {}
115
recognitionCallback(const V2_0_ISoundTriggerHwCallback::RecognitionEvent & event __unused,int32_t cookie __unused)116 Return<void> recognitionCallback(const V2_0_ISoundTriggerHwCallback::RecognitionEvent& event
117 __unused,
118 int32_t cookie __unused) override {
119 ALOGI("%s", __FUNCTION__);
120 return Void();
121 };
122
phraseRecognitionCallback(const V2_0_ISoundTriggerHwCallback::PhraseRecognitionEvent & event __unused,int32_t cookie __unused)123 Return<void> phraseRecognitionCallback(
124 const V2_0_ISoundTriggerHwCallback::PhraseRecognitionEvent& event __unused,
125 int32_t cookie __unused) override {
126 ALOGI("%s", __FUNCTION__);
127 return Void();
128 };
129
soundModelCallback(const V2_0_ISoundTriggerHwCallback::ModelEvent & event,int32_t cookie __unused)130 Return<void> soundModelCallback(const V2_0_ISoundTriggerHwCallback::ModelEvent& event,
131 int32_t cookie __unused) override {
132 ALOGI("%s", __FUNCTION__);
133 mParent.lastModelEvent_2_0 = event;
134 mParent.monitor.notify();
135 return Void();
136 }
137
recognitionCallback_2_1(const ISoundTriggerHwCallback::RecognitionEvent & event __unused,int32_t cookie __unused)138 Return<void> recognitionCallback_2_1(const ISoundTriggerHwCallback::RecognitionEvent& event
139 __unused,
140 int32_t cookie __unused) override {
141 ALOGI("%s", __FUNCTION__);
142 return Void();
143 }
144
phraseRecognitionCallback_2_1(const ISoundTriggerHwCallback::PhraseRecognitionEvent & event __unused,int32_t cookie __unused)145 Return<void> phraseRecognitionCallback_2_1(
146 const ISoundTriggerHwCallback::PhraseRecognitionEvent& event __unused,
147 int32_t cookie __unused) override {
148 ALOGI("%s", __FUNCTION__);
149 return Void();
150 }
151
soundModelCallback_2_1(const ISoundTriggerHwCallback::ModelEvent & event,int32_t cookie __unused)152 Return<void> soundModelCallback_2_1(const ISoundTriggerHwCallback::ModelEvent& event,
153 int32_t cookie __unused) {
154 ALOGI("%s", __FUNCTION__);
155 mParent.lastModelEvent = event;
156 mParent.monitor.notify();
157 return Void();
158 }
159 };
160
TearDown()161 virtual void TearDown() override {}
162
163 Monitor monitor;
164 // updated by soundModelCallback()
165 V2_0_ISoundTriggerHwCallback::ModelEvent lastModelEvent_2_0;
166 // updated by soundModelCallback_2_1()
167 ISoundTriggerHwCallback::ModelEvent lastModelEvent;
168
169 protected:
170 sp<ISoundTriggerHw> mSoundTriggerHal;
171 sp<SoundTriggerHwCallback> mCallback;
172 };
173
174 /**
175 * Test ISoundTriggerHw::loadPhraseSoundModel_2_1() method
176 *
177 * Verifies that:
178 * - the implementation implements the method
179 * - the implementation returns an error when passed a malformed sound model
180 *
181 * There is no way to verify that implementation actually can load a sound model because each
182 * sound model is vendor specific.
183 */
TEST_P(SoundTriggerHidlTest,LoadInvalidModelFail_2_1)184 TEST_P(SoundTriggerHidlTest, LoadInvalidModelFail_2_1) {
185 Return<void> hidlReturn;
186 int ret = -ENODEV;
187 ISoundTriggerHw::PhraseSoundModel model;
188 SoundModelHandle handle;
189
190 model.common.header.type = SoundModelType::UNKNOWN;
191
192 hidlReturn = mSoundTriggerHal->loadPhraseSoundModel_2_1(model, mCallback, 0,
193 [&](int32_t retval, auto res) {
194 ret = retval;
195 handle = res;
196 });
197
198 EXPECT_TRUE(hidlReturn.isOk());
199 EXPECT_NE(0, ret);
200 EXPECT_FALSE(monitor.wait(SHORT_TIMEOUT_PERIOD));
201 }
202
203 /**
204 * Test ISoundTriggerHw::loadSoundModel() method
205 *
206 * Verifies that:
207 * - the implementation returns an error when passed an empty sound model
208 */
TEST_P(SoundTriggerHidlTest,LoadEmptyGenericSoundModelFail)209 TEST_P(SoundTriggerHidlTest, LoadEmptyGenericSoundModelFail) {
210 int ret = -ENODEV;
211 V2_0_ISoundTriggerHw::SoundModel model;
212 SoundModelHandle handle = 0;
213
214 model.type = SoundModelType::GENERIC;
215
216 Return<void> loadReturn =
217 mSoundTriggerHal->loadSoundModel(model, mCallback, 0, [&](int32_t retval, auto res) {
218 ret = retval;
219 handle = res;
220 });
221
222 EXPECT_TRUE(loadReturn.isOk());
223 EXPECT_NE(0, ret);
224 EXPECT_FALSE(monitor.wait(SHORT_TIMEOUT_PERIOD));
225 }
226
227 /**
228 * Test ISoundTriggerHw::loadSoundModel_2_1() method
229 *
230 * Verifies that:
231 * - the implementation returns error when passed a sound model with random data.
232 */
TEST_P(SoundTriggerHidlTest,LoadEmptyGenericSoundModelFail_2_1)233 TEST_P(SoundTriggerHidlTest, LoadEmptyGenericSoundModelFail_2_1) {
234 int ret = -ENODEV;
235 ISoundTriggerHw::SoundModel model;
236 SoundModelHandle handle = 0;
237
238 model.header.type = SoundModelType::GENERIC;
239
240 Return<void> loadReturn =
241 mSoundTriggerHal->loadSoundModel_2_1(model, mCallback, 0, [&](int32_t retval, auto res) {
242 ret = retval;
243 handle = res;
244 });
245
246 EXPECT_TRUE(loadReturn.isOk());
247 EXPECT_NE(0, ret);
248 EXPECT_FALSE(monitor.wait(SHORT_TIMEOUT_PERIOD));
249 }
250
251 /**
252 * Test ISoundTriggerHw::loadSoundModel_2_1() method
253 *
254 * Verifies that:
255 * - the implementation returns error when passed a sound model with random data.
256 */
TEST_P(SoundTriggerHidlTest,LoadGenericSoundModelFail_2_1)257 TEST_P(SoundTriggerHidlTest, LoadGenericSoundModelFail_2_1) {
258 int ret = -ENODEV;
259 ISoundTriggerHw::SoundModel model;
260 SoundModelHandle handle = 0;
261
262 model.header.type = SoundModelType::GENERIC;
263 sp<IAllocator> ashmem = IAllocator::getService("ashmem");
264 ASSERT_NE(nullptr, ashmem.get());
265 hidl_memory hmemory;
266 int size = 100;
267 Return<void> allocReturn = ashmem->allocate(size, [&](bool success, const hidl_memory& m) {
268 ASSERT_TRUE(success);
269 hmemory = m;
270 });
271 sp<IMemory> memory = ::android::hardware::mapMemory(hmemory);
272 ASSERT_NE(nullptr, memory.get());
273 memory->update();
274 for (uint8_t *p = static_cast<uint8_t*>(static_cast<void*>(memory->getPointer())); size >= 0;
275 p++, size--) {
276 *p = rand();
277 }
278
279 Return<void> loadReturn =
280 mSoundTriggerHal->loadSoundModel_2_1(model, mCallback, 0, [&](int32_t retval, auto res) {
281 ret = retval;
282 handle = res;
283 });
284
285 EXPECT_TRUE(loadReturn.isOk());
286 EXPECT_NE(0, ret);
287 EXPECT_FALSE(monitor.wait(SHORT_TIMEOUT_PERIOD));
288 }
289
290 /**
291 * Test ISoundTriggerHw::startRecognition_2_1() method
292 *
293 * Verifies that:
294 * - the implementation implements the method
295 * - the implementation returns an error when called without a valid loaded sound model
296 *
297 * There is no way to verify that implementation actually starts recognition because no model can
298 * be loaded.
299 */
TEST_P(SoundTriggerHidlTest,StartRecognitionNoModelFail_2_1)300 TEST_P(SoundTriggerHidlTest, StartRecognitionNoModelFail_2_1) {
301 Return<int32_t> hidlReturn(0);
302 SoundModelHandle handle = 0;
303 PhraseRecognitionExtra phrase;
304 ISoundTriggerHw::RecognitionConfig config;
305
306 config.header.captureHandle = 0;
307 config.header.captureDevice = AudioDevice::IN_BUILTIN_MIC;
308 phrase.id = 0;
309 phrase.recognitionModes = (uint32_t)RecognitionMode::VOICE_TRIGGER;
310 phrase.confidenceLevel = 0;
311
312 config.header.phrases.setToExternal(&phrase, 1);
313
314 hidlReturn = mSoundTriggerHal->startRecognition_2_1(handle, config, mCallback, 0);
315
316 EXPECT_TRUE(hidlReturn.isOk());
317 EXPECT_NE(0, hidlReturn);
318 }
319
320 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(SoundTriggerHidlTest);
321 INSTANTIATE_TEST_SUITE_P(
322 PerInstance, SoundTriggerHidlTest,
323 testing::ValuesIn(android::hardware::getAllHalInstanceNames(ISoundTriggerHw::descriptor)),
324 android::hardware::PrintInstanceNameToString);
325