SoundTriggerHwService.cpp revision 8ba53d87a2d311ff4b3f04e30b2e09309ae7421c
1/*
2 * Copyright (C) 2014 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 "SoundTriggerHwService"
18//#define LOG_NDEBUG 0
19
20#include <stdio.h>
21#include <string.h>
22#include <sys/types.h>
23#include <pthread.h>
24
25#include <system/sound_trigger.h>
26#include <cutils/atomic.h>
27#include <cutils/properties.h>
28#include <utils/Errors.h>
29#include <utils/Log.h>
30#include <binder/IServiceManager.h>
31#include <binder/MemoryBase.h>
32#include <binder/MemoryHeapBase.h>
33#include <hardware/hardware.h>
34#include <hardware/sound_trigger.h>
35#include <ServiceUtilities.h>
36#include "SoundTriggerHwService.h"
37
38namespace android {
39
40#ifdef SOUND_TRIGGER_USE_STUB_MODULE
41#define HW_MODULE_PREFIX "stub"
42#else
43#define HW_MODULE_PREFIX "primary"
44#endif
45
46SoundTriggerHwService::SoundTriggerHwService()
47    : BnSoundTriggerHwService(),
48      mNextUniqueId(1)
49{
50}
51
52void SoundTriggerHwService::onFirstRef()
53{
54    const hw_module_t *mod;
55    int rc;
56    sound_trigger_hw_device *dev;
57
58    rc = hw_get_module_by_class(SOUND_TRIGGER_HARDWARE_MODULE_ID, HW_MODULE_PREFIX, &mod);
59    if (rc != 0) {
60        ALOGE("couldn't load sound trigger module %s.%s (%s)",
61              SOUND_TRIGGER_HARDWARE_MODULE_ID, "primary", strerror(-rc));
62        return;
63    }
64    rc = sound_trigger_hw_device_open(mod, &dev);
65    if (rc != 0) {
66        ALOGE("couldn't open sound trigger hw device in %s.%s (%s)",
67              SOUND_TRIGGER_HARDWARE_MODULE_ID, "primary", strerror(-rc));
68        return;
69    }
70    if (dev->common.version != SOUND_TRIGGER_DEVICE_API_VERSION_CURRENT) {
71        ALOGE("wrong sound trigger hw device version %04x", dev->common.version);
72        return;
73    }
74
75    sound_trigger_module_descriptor descriptor;
76    rc = dev->get_properties(dev, &descriptor.properties);
77    if (rc != 0) {
78        ALOGE("could not read implementation properties");
79        return;
80    }
81    descriptor.handle =
82            (sound_trigger_module_handle_t)android_atomic_inc(&mNextUniqueId);
83    ALOGI("loaded default module %s, handle %d", descriptor.properties.description,
84                                                 descriptor.handle);
85
86    sp<ISoundTriggerClient> client;
87    sp<Module> module = new Module(this, dev, descriptor, client);
88    mModules.add(descriptor.handle, module);
89    mCallbackThread = new CallbackThread(this);
90}
91
92SoundTriggerHwService::~SoundTriggerHwService()
93{
94    if (mCallbackThread != 0) {
95        mCallbackThread->exit();
96    }
97    for (size_t i = 0; i < mModules.size(); i++) {
98        sound_trigger_hw_device_close(mModules.valueAt(i)->hwDevice());
99    }
100}
101
102status_t SoundTriggerHwService::listModules(struct sound_trigger_module_descriptor *modules,
103                             uint32_t *numModules)
104{
105    ALOGV("listModules");
106    if (!captureHotwordAllowed()) {
107        return PERMISSION_DENIED;
108    }
109
110    AutoMutex lock(mServiceLock);
111    if (numModules == NULL || (*numModules != 0 && modules == NULL)) {
112        return BAD_VALUE;
113    }
114    size_t maxModules = *numModules;
115    *numModules = mModules.size();
116    for (size_t i = 0; i < mModules.size() && i < maxModules; i++) {
117        modules[i] = mModules.valueAt(i)->descriptor();
118    }
119    return NO_ERROR;
120}
121
122status_t SoundTriggerHwService::attach(const sound_trigger_module_handle_t handle,
123                        const sp<ISoundTriggerClient>& client,
124                        sp<ISoundTrigger>& moduleInterface)
125{
126    ALOGV("attach module %d", handle);
127    if (!captureHotwordAllowed()) {
128        return PERMISSION_DENIED;
129    }
130
131    AutoMutex lock(mServiceLock);
132    moduleInterface.clear();
133    if (client == 0) {
134        return BAD_VALUE;
135    }
136    ssize_t index = mModules.indexOfKey(handle);
137    if (index < 0) {
138        return BAD_VALUE;
139    }
140    sp<Module> module = mModules.valueAt(index);
141
142    module->setClient(client);
143    client->asBinder()->linkToDeath(module);
144    moduleInterface = module;
145
146    return NO_ERROR;
147}
148
149void SoundTriggerHwService::detachModule(sp<Module> module) {
150    ALOGV("detachModule");
151    AutoMutex lock(mServiceLock);
152    module->clearClient();
153}
154
155static const int kDumpLockRetries = 50;
156static const int kDumpLockSleep = 60000;
157
158static bool tryLock(Mutex& mutex)
159{
160    bool locked = false;
161    for (int i = 0; i < kDumpLockRetries; ++i) {
162        if (mutex.tryLock() == NO_ERROR) {
163            locked = true;
164            break;
165        }
166        usleep(kDumpLockSleep);
167    }
168    return locked;
169}
170
171status_t SoundTriggerHwService::dump(int fd, const Vector<String16>& args __unused) {
172    String8 result;
173    if (checkCallingPermission(String16("android.permission.DUMP")) == false) {
174        result.appendFormat("Permission Denial: can't dump SoundTriggerHwService");
175        write(fd, result.string(), result.size());
176    } else {
177        bool locked = tryLock(mServiceLock);
178        // failed to lock - SoundTriggerHwService is probably deadlocked
179        if (!locked) {
180            result.append("SoundTriggerHwService may be deadlocked\n");
181            write(fd, result.string(), result.size());
182        }
183
184        if (locked) mServiceLock.unlock();
185    }
186    return NO_ERROR;
187}
188
189status_t SoundTriggerHwService::onTransact(
190    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) {
191    return BnSoundTriggerHwService::onTransact(code, data, reply, flags);
192}
193
194
195// static
196void SoundTriggerHwService::recognitionCallback(struct sound_trigger_recognition_event *event,
197                                                void *cookie)
198{
199    Module *module = (Module *)cookie;
200    if (module == NULL) {
201        return;
202    }
203    module->sendRecognitionEvent(event);
204}
205
206
207void SoundTriggerHwService::sendRecognitionEvent(const sp<RecognitionEvent>& event)
208{
209    mCallbackThread->sendRecognitionEvent(event);
210}
211
212void SoundTriggerHwService::onRecognitionEvent(const sp<RecognitionEvent>& event)
213{
214    ALOGV("onRecognitionEvent");
215    sp<Module> module;
216    {
217        AutoMutex lock(mServiceLock);
218        module = event->mModule.promote();
219        if (module == 0) {
220            return;
221        }
222    }
223    module->onRecognitionEvent(event->mEventMemory);
224}
225
226// static
227void SoundTriggerHwService::soundModelCallback(struct sound_trigger_model_event *event __unused,
228                                               void *cookie)
229{
230    Module *module = (Module *)cookie;
231
232}
233
234#undef LOG_TAG
235#define LOG_TAG "SoundTriggerHwService::CallbackThread"
236
237SoundTriggerHwService::CallbackThread::CallbackThread(const wp<SoundTriggerHwService>& service)
238    : mService(service)
239{
240}
241
242SoundTriggerHwService::CallbackThread::~CallbackThread()
243{
244    mEventQueue.clear();
245}
246
247void SoundTriggerHwService::CallbackThread::onFirstRef()
248{
249    run("soundTrigger cbk", ANDROID_PRIORITY_URGENT_AUDIO);
250}
251
252bool SoundTriggerHwService::CallbackThread::threadLoop()
253{
254    while (!exitPending()) {
255        sp<RecognitionEvent> event;
256        sp<SoundTriggerHwService> service;
257        {
258            Mutex::Autolock _l(mCallbackLock);
259            while (mEventQueue.isEmpty() && !exitPending()) {
260                ALOGV("CallbackThread::threadLoop() sleep");
261                mCallbackCond.wait(mCallbackLock);
262                ALOGV("CallbackThread::threadLoop() wake up");
263            }
264            if (exitPending()) {
265                break;
266            }
267            event = mEventQueue[0];
268            mEventQueue.removeAt(0);
269            service = mService.promote();
270        }
271        if (service != 0) {
272            service->onRecognitionEvent(event);
273        }
274    }
275    return false;
276}
277
278void SoundTriggerHwService::CallbackThread::exit()
279{
280    Mutex::Autolock _l(mCallbackLock);
281    requestExit();
282    mCallbackCond.broadcast();
283}
284
285void SoundTriggerHwService::CallbackThread::sendRecognitionEvent(
286                        const sp<SoundTriggerHwService::RecognitionEvent>& event)
287{
288    AutoMutex lock(mCallbackLock);
289    mEventQueue.add(event);
290    mCallbackCond.signal();
291}
292
293SoundTriggerHwService::RecognitionEvent::RecognitionEvent(
294                                            sp<IMemory> eventMemory,
295                                            wp<Module> module)
296    : mEventMemory(eventMemory), mModule(module)
297{
298}
299
300SoundTriggerHwService::RecognitionEvent::~RecognitionEvent()
301{
302}
303
304#undef LOG_TAG
305#define LOG_TAG "SoundTriggerHwService::Module"
306
307SoundTriggerHwService::Module::Module(const sp<SoundTriggerHwService>& service,
308                                      sound_trigger_hw_device* hwDevice,
309                                      sound_trigger_module_descriptor descriptor,
310                                      const sp<ISoundTriggerClient>& client)
311 : mService(service), mHwDevice(hwDevice), mDescriptor(descriptor),
312   mClient(client)
313{
314}
315
316SoundTriggerHwService::Module::~Module() {
317}
318
319void SoundTriggerHwService::Module::detach() {
320    ALOGV("detach()");
321    if (!captureHotwordAllowed()) {
322        return;
323    }
324    {
325        AutoMutex lock(mLock);
326        for (size_t i = 0; i < mModels.size(); i++) {
327            sp<Model> model = mModels.valueAt(i);
328            ALOGV("detach() unloading model %d", model->mHandle);
329            if (model->mState == Model::STATE_ACTIVE) {
330                mHwDevice->stop_recognition(mHwDevice, model->mHandle);
331                model->deallocateMemory();
332            }
333            mHwDevice->unload_sound_model(mHwDevice, model->mHandle);
334        }
335        mModels.clear();
336    }
337    if (mClient != 0) {
338        mClient->asBinder()->unlinkToDeath(this);
339    }
340    sp<SoundTriggerHwService> service = mService.promote();
341    if (service == 0) {
342        return;
343    }
344    service->detachModule(this);
345}
346
347status_t SoundTriggerHwService::Module::loadSoundModel(const sp<IMemory>& modelMemory,
348                                sound_model_handle_t *handle)
349{
350    ALOGV("loadSoundModel() handle");
351    if (!captureHotwordAllowed()) {
352        return PERMISSION_DENIED;
353    }
354
355    if (modelMemory == 0 || modelMemory->pointer() == NULL) {
356        ALOGE("loadSoundModel() modelMemory is 0 or has NULL pointer()");
357        return BAD_VALUE;
358    }
359    struct sound_trigger_sound_model *sound_model =
360            (struct sound_trigger_sound_model *)modelMemory->pointer();
361
362    AutoMutex lock(mLock);
363    status_t status = mHwDevice->load_sound_model(mHwDevice,
364                                                  sound_model,
365                                                  SoundTriggerHwService::soundModelCallback,
366                                                  this,
367                                                  handle);
368    if (status == NO_ERROR) {
369        mModels.replaceValueFor(*handle, new Model(*handle));
370    }
371
372    return status;
373}
374
375status_t SoundTriggerHwService::Module::unloadSoundModel(sound_model_handle_t handle)
376{
377    ALOGV("unloadSoundModel() model handle %d", handle);
378    if (!captureHotwordAllowed()) {
379        return PERMISSION_DENIED;
380    }
381
382    AutoMutex lock(mLock);
383    ssize_t index = mModels.indexOfKey(handle);
384    if (index < 0) {
385        return BAD_VALUE;
386    }
387    sp<Model> model = mModels.valueAt(index);
388    mModels.removeItem(handle);
389    if (model->mState == Model::STATE_ACTIVE) {
390        mHwDevice->stop_recognition(mHwDevice, model->mHandle);
391        model->deallocateMemory();
392    }
393    return mHwDevice->unload_sound_model(mHwDevice, handle);
394}
395
396status_t SoundTriggerHwService::Module::startRecognition(sound_model_handle_t handle,
397                                 const sp<IMemory>& dataMemory)
398{
399    ALOGV("startRecognition() model handle %d", handle);
400    if (!captureHotwordAllowed()) {
401        return PERMISSION_DENIED;
402    }
403
404    if (dataMemory != 0 && dataMemory->pointer() == NULL) {
405        ALOGE("startRecognition() dataMemory is non-0 but has NULL pointer()");
406        return BAD_VALUE;
407
408    }
409    AutoMutex lock(mLock);
410    sp<Model> model = getModel(handle);
411    if (model == 0) {
412        return BAD_VALUE;
413    }
414    if ((dataMemory == 0) ||
415            (dataMemory->size() < sizeof(struct sound_trigger_recognition_config))) {
416        return BAD_VALUE;
417    }
418
419    if (model->mState == Model::STATE_ACTIVE) {
420        return INVALID_OPERATION;
421    }
422    model->mState = Model::STATE_ACTIVE;
423
424    struct sound_trigger_recognition_config *config =
425            (struct sound_trigger_recognition_config *)dataMemory->pointer();
426
427    //TODO: get capture handle and device from audio policy service
428    config->capture_handle = AUDIO_IO_HANDLE_NONE;
429    config->capture_device = AUDIO_DEVICE_NONE;
430    return mHwDevice->start_recognition(mHwDevice, handle, config,
431                                        SoundTriggerHwService::recognitionCallback,
432                                        this);
433}
434
435status_t SoundTriggerHwService::Module::stopRecognition(sound_model_handle_t handle)
436{
437    ALOGV("stopRecognition() model handle %d", handle);
438    if (!captureHotwordAllowed()) {
439        return PERMISSION_DENIED;
440    }
441
442    AutoMutex lock(mLock);
443    sp<Model> model = getModel(handle);
444    if (model == 0) {
445        return BAD_VALUE;
446    }
447
448    if (model->mState != Model::STATE_ACTIVE) {
449        return INVALID_OPERATION;
450    }
451    mHwDevice->stop_recognition(mHwDevice, handle);
452    model->deallocateMemory();
453    model->mState = Model::STATE_IDLE;
454    return NO_ERROR;
455}
456
457void SoundTriggerHwService::Module::sendRecognitionEvent(
458                                                    struct sound_trigger_recognition_event *event)
459{
460    sp<SoundTriggerHwService> service;
461    sp<IMemory> eventMemory;
462    ALOGV("sendRecognitionEvent for model %d", event->model);
463    {
464        AutoMutex lock(mLock);
465        sp<Model> model = getModel(event->model);
466        if (model == 0) {
467            return;
468        }
469        if (model->mState != Model::STATE_ACTIVE) {
470            ALOGV("sendRecognitionEvent model->mState %d != Model::STATE_ACTIVE", model->mState);
471            return;
472        }
473        if (mClient == 0) {
474            return;
475        }
476        service = mService.promote();
477        if (service == 0) {
478            return;
479        }
480
481        //sanitize event
482        switch (event->type) {
483        case SOUND_MODEL_TYPE_KEYPHRASE:
484            ALOGW_IF(event->data_offset !=
485                        sizeof(struct sound_trigger_phrase_recognition_event),
486                        "sendRecognitionEvent(): invalid data offset %u for keyphrase event type",
487                        event->data_offset);
488            event->data_offset = sizeof(struct sound_trigger_phrase_recognition_event);
489            break;
490        case SOUND_MODEL_TYPE_UNKNOWN:
491            ALOGW_IF(event->data_offset !=
492                        sizeof(struct sound_trigger_recognition_event),
493                        "sendRecognitionEvent(): invalid data offset %u for unknown event type",
494                        event->data_offset);
495            event->data_offset = sizeof(struct sound_trigger_recognition_event);
496            break;
497        default:
498                return;
499        }
500
501        size_t size = event->data_offset + event->data_size;
502        eventMemory = model->allocateMemory(size);
503        if (eventMemory == 0 || eventMemory->pointer() == NULL) {
504            return;
505        }
506        memcpy(eventMemory->pointer(), event, size);
507    }
508    service->sendRecognitionEvent(new RecognitionEvent(eventMemory, this));
509}
510
511void SoundTriggerHwService::Module::onRecognitionEvent(sp<IMemory> eventMemory)
512{
513    ALOGV("Module::onRecognitionEvent");
514
515    AutoMutex lock(mLock);
516
517    if (eventMemory == 0 || eventMemory->pointer() == NULL) {
518        return;
519    }
520    struct sound_trigger_recognition_event *event =
521            (struct sound_trigger_recognition_event *)eventMemory->pointer();
522
523    sp<Model> model = getModel(event->model);
524    if (model == 0) {
525        ALOGI("%s model == 0", __func__);
526        return;
527    }
528    if (model->mState != Model::STATE_ACTIVE) {
529        ALOGV("onRecognitionEvent model->mState %d != Model::STATE_ACTIVE", model->mState);
530        return;
531    }
532    if (mClient == 0) {
533        ALOGI("%s mClient == 0", __func__);
534        return;
535    }
536    mClient->onRecognitionEvent(eventMemory);
537    model->mState = Model::STATE_IDLE;
538    model->deallocateMemory();
539}
540
541sp<SoundTriggerHwService::Model> SoundTriggerHwService::Module::getModel(
542        sound_model_handle_t handle)
543{
544    sp<Model> model;
545    ssize_t index = mModels.indexOfKey(handle);
546    if (index >= 0) {
547        model = mModels.valueAt(index);
548    }
549    return model;
550}
551
552void SoundTriggerHwService::Module::binderDied(
553    const wp<IBinder> &who __unused) {
554    ALOGW("client binder died for module %d", mDescriptor.handle);
555    detach();
556}
557
558
559SoundTriggerHwService::Model::Model(sound_model_handle_t handle) :
560    mHandle(handle), mState(STATE_IDLE), mInputHandle(AUDIO_IO_HANDLE_NONE),
561    mCaptureSession(AUDIO_SESSION_ALLOCATE),
562    mMemoryDealer(new MemoryDealer(sizeof(struct sound_trigger_recognition_event),
563                                   "SoundTriggerHwService::Event"))
564{
565
566}
567
568
569sp<IMemory> SoundTriggerHwService::Model::allocateMemory(size_t size)
570{
571    sp<IMemory> memory;
572    if (mMemoryDealer->getMemoryHeap()->getSize() < size) {
573        mMemoryDealer = new MemoryDealer(size, "SoundTriggerHwService::Event");
574    }
575    memory = mMemoryDealer->allocate(size);
576    return memory;
577}
578
579void SoundTriggerHwService::Model::deallocateMemory()
580{
581    mMemoryDealer->deallocate(0);
582}
583
584status_t SoundTriggerHwService::Module::dump(int fd __unused,
585                                             const Vector<String16>& args __unused) {
586    String8 result;
587    return NO_ERROR;
588}
589
590}; // namespace android
591