1/*
2 * Copyright (C) 2015 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 "RadioService"
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/audio.h>
26#include <system/audio_policy.h>
27#include <system/radio.h>
28#include <system/radio_metadata.h>
29#include <cutils/atomic.h>
30#include <cutils/properties.h>
31#include <hardware/hardware.h>
32#include <utils/Errors.h>
33#include <utils/Log.h>
34#include <binder/IServiceManager.h>
35#include <binder/MemoryBase.h>
36#include <binder/MemoryHeapBase.h>
37#include <binder/PermissionCache.h>
38#include <hardware/radio.h>
39#include <media/AudioSystem.h>
40#include "RadioService.h"
41#include "RadioRegions.h"
42
43namespace android {
44
45static const char kRadioTunerAudioDeviceName[] = "Radio tuner source";
46
47static const String16 RADIO_PERMISSION("android.permission.ACCESS_FM_RADIO");
48
49RadioService::RadioService()
50    : BnRadioService(), mNextUniqueId(1)
51{
52    ALOGI("%s", __FUNCTION__);
53}
54
55void RadioService::onFirstRef()
56{
57    ALOGI("%s", __FUNCTION__);
58
59    sp<RadioInterface> dev = RadioInterface::connectModule(RADIO_CLASS_AM_FM);
60
61    if (dev == 0) {
62        return;
63    }
64    struct radio_hal_properties halProperties;
65    int rc = dev->getProperties(&halProperties);
66    if (rc != 0) {
67        ALOGE("could not read implementation properties");
68        return;
69    }
70
71    radio_properties_t properties;
72    properties.handle =
73            (radio_handle_t)android_atomic_inc(&mNextUniqueId);
74    convertProperties(&properties, &halProperties);
75
76    ALOGI("loaded default module %s, ver %s, handle %d", properties.product,
77        properties.version, properties.handle);
78
79    sp<Module> module = new Module(dev, properties);
80    mModules.add(properties.handle, module);
81}
82
83RadioService::~RadioService()
84{
85}
86
87status_t RadioService::listModules(struct radio_properties *properties,
88                             uint32_t *numModules)
89{
90    if (!PermissionCache::checkCallingPermission(RADIO_PERMISSION)) {
91        return PERMISSION_DENIED;
92    }
93    ALOGV("listModules");
94
95    AutoMutex lock(mServiceLock);
96    if (numModules == NULL || (*numModules != 0 && properties == NULL)) {
97        return BAD_VALUE;
98    }
99    uint32_t maxModules = *numModules;
100    *numModules = mModules.size();
101    for (size_t i = 0; i < mModules.size() && i < maxModules; i++) {
102        properties[i] = mModules.valueAt(i)->properties();
103    }
104    return NO_ERROR;
105}
106
107status_t RadioService::attach(radio_handle_t handle,
108                        const sp<IRadioClient>& client,
109                        const struct radio_band_config *config,
110                        bool withAudio,
111                        sp<IRadio>& radio)
112{
113    if (!PermissionCache::checkCallingPermission(RADIO_PERMISSION)) {
114        return PERMISSION_DENIED;
115    }
116    ALOGV("%s %d config %p withAudio %d", __FUNCTION__, handle, config, withAudio);
117
118    AutoMutex lock(mServiceLock);
119    radio.clear();
120    if (client == 0) {
121        return BAD_VALUE;
122    }
123    ssize_t index = mModules.indexOfKey(handle);
124    if (index < 0) {
125        return BAD_VALUE;
126    }
127    sp<Module> module = mModules.valueAt(index);
128
129    if (config == NULL) {
130        config = module->getDefaultConfig();
131        if (config == NULL) {
132            return INVALID_OPERATION;
133        }
134    }
135    ALOGV("%s region %d type %d", __FUNCTION__, config->region, config->band.type);
136
137    radio = module->addClient(client, config, withAudio);
138
139    if (radio == 0) {
140        return NO_INIT;
141    }
142    return NO_ERROR;
143}
144
145
146static const int kDumpLockRetries = 50;
147static const int kDumpLockSleep = 60000;
148
149static bool tryLock(Mutex& mutex)
150{
151    bool locked = false;
152    for (int i = 0; i < kDumpLockRetries; ++i) {
153        if (mutex.tryLock() == NO_ERROR) {
154            locked = true;
155            break;
156        }
157        usleep(kDumpLockSleep);
158    }
159    return locked;
160}
161
162status_t RadioService::dump(int fd, const Vector<String16>& args __unused) {
163    String8 result;
164    if (checkCallingPermission(String16("android.permission.DUMP")) == false) {
165        result.appendFormat("Permission Denial: can't dump RadioService");
166        write(fd, result.string(), result.size());
167    } else {
168        bool locked = tryLock(mServiceLock);
169        // failed to lock - RadioService is probably deadlocked
170        if (!locked) {
171            result.append("RadioService may be deadlocked\n");
172            write(fd, result.string(), result.size());
173        }
174
175        if (locked) mServiceLock.unlock();
176    }
177    return NO_ERROR;
178}
179
180status_t RadioService::onTransact(
181    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) {
182    return BnRadioService::onTransact(code, data, reply, flags);
183}
184
185
186/* static */
187void RadioService::convertProperties(radio_properties_t *properties,
188                                     const radio_hal_properties_t *halProperties)
189{
190    memset(properties, 0, sizeof(struct radio_properties));
191    properties->class_id = halProperties->class_id;
192    strlcpy(properties->implementor, halProperties->implementor,
193            RADIO_STRING_LEN_MAX);
194    strlcpy(properties->product, halProperties->product,
195            RADIO_STRING_LEN_MAX);
196    strlcpy(properties->version, halProperties->version,
197            RADIO_STRING_LEN_MAX);
198    strlcpy(properties->serial, halProperties->serial,
199            RADIO_STRING_LEN_MAX);
200    properties->num_tuners = halProperties->num_tuners;
201    properties->num_audio_sources = halProperties->num_audio_sources;
202    properties->supports_capture = halProperties->supports_capture;
203
204    for (size_t i = 0; i < ARRAY_SIZE(sKnownRegionConfigs); i++) {
205        const radio_hal_band_config_t *band = &sKnownRegionConfigs[i].band;
206        size_t j;
207        for (j = 0; j < halProperties->num_bands; j++) {
208            const radio_hal_band_config_t *halBand = &halProperties->bands[j];
209            size_t k;
210            if (band->type != halBand->type) continue;
211            if (band->lower_limit < halBand->lower_limit) continue;
212            if (band->upper_limit > halBand->upper_limit) continue;
213            for (k = 0; k < halBand->num_spacings; k++) {
214                if (band->spacings[0] == halBand->spacings[k]) break;
215            }
216            if (k == halBand->num_spacings) continue;
217            if (band->type == RADIO_BAND_AM) break;
218            if ((band->fm.deemphasis & halBand->fm.deemphasis) == 0) continue;
219            if (halBand->fm.rds == 0) break;
220            if ((band->fm.rds & halBand->fm.rds) != 0) break;
221        }
222        if (j == halProperties->num_bands) continue;
223
224        ALOGI("convertProperties() Adding band type %d region %d",
225              sKnownRegionConfigs[i].band.type , sKnownRegionConfigs[i].region);
226
227        memcpy(&properties->bands[properties->num_bands++],
228               &sKnownRegionConfigs[i],
229               sizeof(radio_band_config_t));
230    }
231}
232
233#undef LOG_TAG
234#define LOG_TAG "RadioService::CallbackThread"
235
236RadioService::CallbackThread::CallbackThread(const wp<ModuleClient>& moduleClient)
237    : mModuleClient(moduleClient), mMemoryDealer(new MemoryDealer(1024 * 1024, "RadioService"))
238{
239}
240
241RadioService::CallbackThread::~CallbackThread()
242{
243    mEventQueue.clear();
244}
245
246void RadioService::CallbackThread::onFirstRef()
247{
248    run("RadioService cbk", ANDROID_PRIORITY_URGENT_AUDIO);
249}
250
251bool RadioService::CallbackThread::threadLoop()
252{
253    while (!exitPending()) {
254        sp<IMemory> eventMemory;
255        sp<ModuleClient> moduleClient;
256        {
257            Mutex::Autolock _l(mCallbackLock);
258            while (mEventQueue.isEmpty() && !exitPending()) {
259                ALOGV("CallbackThread::threadLoop() sleep");
260                mCallbackCond.wait(mCallbackLock);
261                ALOGV("CallbackThread::threadLoop() wake up");
262            }
263            if (exitPending()) {
264                break;
265            }
266            eventMemory = mEventQueue[0];
267            mEventQueue.removeAt(0);
268            moduleClient = mModuleClient.promote();
269        }
270        if (moduleClient != 0) {
271            moduleClient->onCallbackEvent(eventMemory);
272            eventMemory.clear();
273        }
274    }
275    return false;
276}
277
278void RadioService::CallbackThread::exit()
279{
280    Mutex::Autolock _l(mCallbackLock);
281    requestExit();
282    mCallbackCond.broadcast();
283}
284
285sp<IMemory> RadioService::CallbackThread::prepareEvent(radio_hal_event_t *halEvent)
286{
287    sp<IMemory> eventMemory;
288
289    // The event layout in shared memory is:
290    // sizeof(struct radio_event) bytes : the event itself
291    // 4 bytes                          : metadata size or 0
292    // N bytes                          : metadata if present
293    uint32_t metadataOffset = sizeof(struct radio_event) + sizeof(uint32_t);
294    uint32_t metadataSize = 0;
295
296    switch (halEvent->type) {
297    case RADIO_EVENT_TUNED:
298    case RADIO_EVENT_AF_SWITCH:
299        if (radio_metadata_check(halEvent->info.metadata) == 0) {
300            metadataSize = (uint32_t)radio_metadata_get_size(halEvent->info.metadata);
301        }
302        break;
303    case RADIO_EVENT_METADATA:
304        if (radio_metadata_check(halEvent->metadata) != 0) {
305            return eventMemory;
306        }
307        metadataSize = (uint32_t)radio_metadata_get_size(halEvent->metadata);
308        break;
309    default:
310        break;
311    }
312
313    eventMemory = mMemoryDealer->allocate(metadataOffset + metadataSize);
314    if (eventMemory == 0 || eventMemory->pointer() == NULL) {
315        eventMemory.clear();
316        return eventMemory;
317    }
318
319    struct radio_event *event = (struct radio_event *)eventMemory->pointer();
320
321    *(uint32_t *)((uint8_t *)event + metadataOffset - sizeof(uint32_t)) = metadataSize;
322
323    event->type = halEvent->type;
324    event->status = halEvent->status;
325
326    switch (event->type) {
327    case RADIO_EVENT_CONFIG:
328        event->config.band = halEvent->config;
329        break;
330    case RADIO_EVENT_TUNED:
331    case RADIO_EVENT_AF_SWITCH:
332        event->info = halEvent->info;
333        if (metadataSize != 0) {
334            memcpy((uint8_t *)event + metadataOffset, halEvent->info.metadata, metadataSize);
335        }
336        break;
337    case RADIO_EVENT_TA:
338    case RADIO_EVENT_EA:
339    case RADIO_EVENT_ANTENNA:
340    case RADIO_EVENT_CONTROL:
341        event->on = halEvent->on;
342        break;
343    case RADIO_EVENT_METADATA:
344        if (metadataSize != 0) {
345            memcpy((uint8_t *)event + metadataOffset, halEvent->metadata, metadataSize);
346        }
347        break;
348    case RADIO_EVENT_HW_FAILURE:
349    default:
350        break;
351    }
352
353    return eventMemory;
354}
355
356void RadioService::CallbackThread::sendEvent(radio_hal_event_t *event)
357 {
358     sp<IMemory> eventMemory = prepareEvent(event);
359     if (eventMemory == 0) {
360         return;
361     }
362
363     AutoMutex lock(mCallbackLock);
364     mEventQueue.add(eventMemory);
365     mCallbackCond.signal();
366     ALOGV("%s DONE", __FUNCTION__);
367}
368
369
370#undef LOG_TAG
371#define LOG_TAG "RadioService::Module"
372
373RadioService::Module::Module(sp<RadioInterface> hwDevice, radio_properties properties)
374 : mHwDevice(hwDevice), mProperties(properties), mMute(true)
375{
376}
377
378RadioService::Module::~Module() {
379    mHwDevice.clear();
380    mModuleClients.clear();
381}
382
383status_t RadioService::Module::dump(int fd __unused, const Vector<String16>& args __unused) {
384    String8 result;
385    return NO_ERROR;
386}
387
388sp<RadioService::ModuleClient> RadioService::Module::addClient(const sp<IRadioClient>& client,
389                                    const struct radio_band_config *config,
390                                    bool audio)
391{
392    ALOGV("addClient() %p config %p product %s", this, config, mProperties.product);
393
394    AutoMutex lock(mLock);
395    sp<ModuleClient> moduleClient;
396    int ret;
397
398    if (mHwDevice == 0) {
399        return moduleClient;
400    }
401
402    for (size_t i = 0; i < mModuleClients.size(); i++) {
403        if (mModuleClients[i]->client() == client) {
404            // client already connected: reject
405            return moduleClient;
406        }
407    }
408    moduleClient = new ModuleClient(this, client, config, audio);
409
410    struct radio_hal_band_config halConfig;
411    halConfig = config->band;
412
413    // Tuner preemption logic:
414    // There is a limited amount of tuners and a limited amount of radio audio sources per module.
415    // The minimum is one tuner and one audio source.
416    // The numbers of tuners and sources are indicated in the module properties.
417    // NOTE: current framework implementation only supports one radio audio source.
418    // It is possible to open more than one tuner at a time but only one tuner can be connected
419    // to the radio audio source (AUDIO_DEVICE_IN_FM_TUNER).
420    // The base rule is that a newly connected tuner always wins, i.e. always gets a tuner
421    // and can use the audio source if requested.
422    // If another client is preempted, it is notified by a callback with RADIO_EVENT_CONTROL
423    // indicating loss of control.
424    // - If the newly connected client requests the audio source (audio == true):
425    //    - if an audio source is available
426    //          no problem
427    //    - if not:
428    //          the oldest client in the list using audio is preempted.
429    // - If the newly connected client does not request the audio source (audio == false):
430    //    - if a tuner is available
431    //          no problem
432    //    - if not:
433    //          The oldest client not using audio is preempted first and if none is found the
434    //          the oldest client using audio is preempted.
435    // Each time a tuner using the audio source is opened or closed, the audio policy manager is
436    // notified of the connection or disconnection of AUDIO_DEVICE_IN_FM_TUNER.
437
438    sp<ModuleClient> oldestTuner;
439    sp<ModuleClient> oldestAudio;
440    size_t allocatedTuners = 0;
441    size_t allocatedAudio = 0;
442    for (size_t i = 0; i < mModuleClients.size(); i++) {
443        if (mModuleClients[i]->getTuner() != NULL) {
444            if (mModuleClients[i]->audio()) {
445                if (oldestAudio == 0) {
446                    oldestAudio = mModuleClients[i];
447                }
448                allocatedAudio++;
449            } else {
450                if (oldestTuner == 0) {
451                    oldestTuner = mModuleClients[i];
452                }
453                allocatedTuners++;
454            }
455        }
456    }
457
458    sp<TunerInterface> halTuner;
459    sp<ModuleClient> preemtedClient;
460    if (audio) {
461        if (allocatedAudio >= mProperties.num_audio_sources) {
462            ALOG_ASSERT(oldestAudio != 0, "addClient() allocatedAudio/oldestAudio mismatch");
463            preemtedClient = oldestAudio;
464        }
465    } else {
466        if (allocatedAudio + allocatedTuners >= mProperties.num_tuners) {
467            if (allocatedTuners != 0) {
468                ALOG_ASSERT(oldestTuner != 0, "addClient() allocatedTuners/oldestTuner mismatch");
469                preemtedClient = oldestTuner;
470            } else {
471                ALOG_ASSERT(oldestAudio != 0, "addClient() allocatedAudio/oldestAudio mismatch");
472                preemtedClient = oldestAudio;
473            }
474        }
475    }
476    if (preemtedClient != 0) {
477        halTuner = preemtedClient->getTuner();
478        sp<TunerInterface> clear;
479        preemtedClient->setTuner(clear);
480        mHwDevice->closeTuner(halTuner);
481        if (preemtedClient->audio()) {
482            notifyDeviceConnection(false, "");
483        }
484    }
485
486    ret = mHwDevice->openTuner(&halConfig, audio,
487                               moduleClient,
488                               halTuner);
489    if (ret == 0) {
490        ALOGV("addClient() setTuner %p", halTuner.get());
491        moduleClient->setTuner(halTuner);
492        mModuleClients.add(moduleClient);
493        if (audio) {
494            notifyDeviceConnection(true, "");
495        }
496        ALOGV("addClient() DONE moduleClient %p", moduleClient.get());
497    } else {
498        ALOGW("%s open_tuner failed with error %d", __FUNCTION__, ret);
499        moduleClient.clear();
500    }
501
502    return moduleClient;
503}
504
505void RadioService::Module::removeClient(const sp<ModuleClient>& moduleClient) {
506    ALOGV("removeClient()");
507    AutoMutex lock(mLock);
508    int ret;
509    ssize_t index = -1;
510
511    for (size_t i = 0; i < mModuleClients.size(); i++) {
512        if (mModuleClients[i] == moduleClient) {
513            index = i;
514            break;
515        }
516    }
517    if (index == -1) {
518        return;
519    }
520
521    mModuleClients.removeAt(index);
522    sp<TunerInterface> halTuner = moduleClient->getTuner();
523    if (halTuner == NULL) {
524        return;
525    }
526
527    if (mHwDevice != 0) {
528        mHwDevice->closeTuner(halTuner);
529    }
530
531    if (moduleClient->audio()) {
532        notifyDeviceConnection(false, "");
533    }
534
535    mMute = true;
536
537    if (mModuleClients.isEmpty()) {
538        return;
539    }
540
541    if (mHwDevice == 0) {
542        return;
543    }
544
545    // Tuner reallocation logic:
546    // When a client is removed and was controlling a tuner, this tuner will be allocated to a
547    // previously preempted client. This client will be notified by a callback with
548    // RADIO_EVENT_CONTROL indicating gain of control.
549    // - If a preempted client is waiting for an audio source and one becomes available:
550    //    Allocate the tuner to the most recently added client waiting for an audio source
551    // - If not:
552    //    Allocate the tuner to the most recently added client.
553    // Each time a tuner using the audio source is opened or closed, the audio policy manager is
554    // notified of the connection or disconnection of AUDIO_DEVICE_IN_FM_TUNER.
555
556    sp<ModuleClient> youngestClient;
557    sp<ModuleClient> youngestClientAudio;
558    size_t allocatedTuners = 0;
559    size_t allocatedAudio = 0;
560    for (ssize_t i = mModuleClients.size() - 1; i >= 0; i--) {
561        if (mModuleClients[i]->getTuner() == NULL) {
562            if (mModuleClients[i]->audio()) {
563                if (youngestClientAudio == 0) {
564                    youngestClientAudio = mModuleClients[i];
565                }
566            } else {
567                if (youngestClient == 0) {
568                    youngestClient = mModuleClients[i];
569                }
570            }
571        } else {
572            if (mModuleClients[i]->audio()) {
573                allocatedAudio++;
574            } else {
575                allocatedTuners++;
576            }
577        }
578    }
579
580    ALOG_ASSERT(allocatedTuners + allocatedAudio < mProperties.num_tuners,
581                "removeClient() removed client but no tuner available");
582
583    ALOG_ASSERT(!moduleClient->audio() || allocatedAudio < mProperties.num_audio_sources,
584                "removeClient() removed audio client but no tuner with audio available");
585
586    if (allocatedAudio < mProperties.num_audio_sources && youngestClientAudio != 0) {
587        youngestClient = youngestClientAudio;
588    }
589
590    ALOG_ASSERT(youngestClient != 0, "removeClient() removed client no candidate found for tuner");
591
592    struct radio_hal_band_config halConfig = youngestClient->halConfig();
593    ret = mHwDevice->openTuner(&halConfig, youngestClient->audio(),
594                                moduleClient,
595                                halTuner);
596
597    if (ret == 0) {
598        youngestClient->setTuner(halTuner);
599        if (youngestClient->audio()) {
600            notifyDeviceConnection(true, "");
601        }
602    }
603}
604
605status_t RadioService::Module::setMute(bool mute)
606{
607    Mutex::Autolock _l(mLock);
608    if (mute != mMute) {
609        mMute = mute;
610        //TODO notifify audio policy manager of media activity on radio audio device
611    }
612    return NO_ERROR;
613}
614
615status_t RadioService::Module::getMute(bool *mute)
616{
617    Mutex::Autolock _l(mLock);
618    *mute = mMute;
619    return NO_ERROR;
620}
621
622
623const struct radio_band_config *RadioService::Module::getDefaultConfig() const
624{
625    if (mProperties.num_bands == 0) {
626        return NULL;
627    }
628    return &mProperties.bands[0];
629}
630
631void RadioService::Module::notifyDeviceConnection(bool connected,
632                                                  const char *address) {
633    int64_t token = IPCThreadState::self()->clearCallingIdentity();
634    AudioSystem::setDeviceConnectionState(AUDIO_DEVICE_IN_FM_TUNER,
635                                          connected ? AUDIO_POLICY_DEVICE_STATE_AVAILABLE :
636                                                  AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE,
637                                          address, kRadioTunerAudioDeviceName);
638    IPCThreadState::self()->restoreCallingIdentity(token);
639}
640
641#undef LOG_TAG
642#define LOG_TAG "RadioService::ModuleClient"
643
644RadioService::ModuleClient::ModuleClient(const sp<Module>& module,
645                                         const sp<IRadioClient>& client,
646                                         const struct radio_band_config *config,
647                                         bool audio)
648 : mModule(module), mClient(client), mConfig(*config), mAudio(audio), mTuner(0)
649{
650}
651
652void RadioService::ModuleClient::onFirstRef()
653{
654    mCallbackThread = new CallbackThread(this);
655    IInterface::asBinder(mClient)->linkToDeath(this);
656}
657
658RadioService::ModuleClient::~ModuleClient() {
659    if (mClient != 0) {
660        IInterface::asBinder(mClient)->unlinkToDeath(this);
661        mClient.clear();
662    }
663    if (mCallbackThread != 0) {
664        mCallbackThread->exit();
665    }
666}
667
668void RadioService::ModuleClient::onEvent(radio_hal_event_t *halEvent)
669{
670    mCallbackThread->sendEvent(halEvent);
671}
672
673status_t RadioService::ModuleClient::dump(int fd __unused,
674                                             const Vector<String16>& args __unused) {
675    String8 result;
676    return NO_ERROR;
677}
678
679void RadioService::ModuleClient::detach() {
680    ALOGV("%s", __FUNCTION__);
681    sp<ModuleClient> strongMe = this;
682    {
683        AutoMutex lock(mLock);
684        if (mClient != 0) {
685            IInterface::asBinder(mClient)->unlinkToDeath(this);
686            mClient.clear();
687        }
688    }
689    sp<Module> module = mModule.promote();
690    if (module == 0) {
691        return;
692    }
693    module->removeClient(this);
694}
695
696radio_hal_band_config_t RadioService::ModuleClient::halConfig() const
697{
698    AutoMutex lock(mLock);
699    ALOGV("%s locked", __FUNCTION__);
700    return mConfig.band;
701}
702
703sp<TunerInterface>& RadioService::ModuleClient::getTuner()
704{
705    AutoMutex lock(mLock);
706    ALOGV("%s locked", __FUNCTION__);
707    return mTuner;
708}
709
710void RadioService::ModuleClient::setTuner(sp<TunerInterface>& tuner)
711{
712    ALOGV("%s %p", __FUNCTION__, this);
713
714    AutoMutex lock(mLock);
715    mTuner = tuner;
716    ALOGV("%s locked", __FUNCTION__);
717
718    radio_hal_event_t event;
719    event.type = RADIO_EVENT_CONTROL;
720    event.status = 0;
721    event.on = mTuner != 0;
722    mCallbackThread->sendEvent(&event);
723    ALOGV("%s DONE", __FUNCTION__);
724
725}
726
727status_t RadioService::ModuleClient::setConfiguration(const struct radio_band_config *config)
728{
729    if (!PermissionCache::checkCallingPermission(RADIO_PERMISSION)) {
730        return PERMISSION_DENIED;
731    }
732    AutoMutex lock(mLock);
733    status_t status = NO_ERROR;
734    ALOGV("%s locked", __FUNCTION__);
735
736    if (mTuner != 0) {
737        struct radio_hal_band_config halConfig;
738        halConfig = config->band;
739        status = (status_t)mTuner->setConfiguration(&halConfig);
740        if (status == NO_ERROR) {
741            mConfig = *config;
742        }
743    } else {
744        mConfig = *config;
745        status = INVALID_OPERATION;
746    }
747
748    return status;
749}
750
751status_t RadioService::ModuleClient::getConfiguration(struct radio_band_config *config)
752{
753    if (!PermissionCache::checkCallingPermission(RADIO_PERMISSION)) {
754        return PERMISSION_DENIED;
755    }
756    AutoMutex lock(mLock);
757    status_t status = NO_ERROR;
758    ALOGV("%s locked", __FUNCTION__);
759
760    if (mTuner != 0) {
761        struct radio_hal_band_config halConfig;
762        status = (status_t)mTuner->getConfiguration(&halConfig);
763        if (status == NO_ERROR) {
764            mConfig.band = halConfig;
765        }
766    }
767    *config = mConfig;
768
769    return status;
770}
771
772status_t RadioService::ModuleClient::setMute(bool mute)
773{
774    if (!PermissionCache::checkCallingPermission(RADIO_PERMISSION)) {
775        return PERMISSION_DENIED;
776    }
777    sp<Module> module;
778    {
779        Mutex::Autolock _l(mLock);
780        ALOGV("%s locked", __FUNCTION__);
781        if (mTuner == 0 || !mAudio) {
782            return INVALID_OPERATION;
783        }
784        module = mModule.promote();
785        if (module == 0) {
786            return NO_INIT;
787        }
788    }
789    module->setMute(mute);
790    return NO_ERROR;
791}
792
793status_t RadioService::ModuleClient::getMute(bool *mute)
794{
795    if (!PermissionCache::checkCallingPermission(RADIO_PERMISSION)) {
796        return PERMISSION_DENIED;
797    }
798    sp<Module> module;
799    {
800        Mutex::Autolock _l(mLock);
801        ALOGV("%s locked", __FUNCTION__);
802        module = mModule.promote();
803        if (module == 0) {
804            return NO_INIT;
805        }
806    }
807    return module->getMute(mute);
808}
809
810status_t RadioService::ModuleClient::scan(radio_direction_t direction, bool skipSubChannel)
811{
812    if (!PermissionCache::checkCallingPermission(RADIO_PERMISSION)) {
813        return PERMISSION_DENIED;
814    }
815    AutoMutex lock(mLock);
816    ALOGV("%s locked", __FUNCTION__);
817    status_t status;
818    if (mTuner != 0) {
819        status = (status_t)mTuner->scan(direction, skipSubChannel);
820    } else {
821        status = INVALID_OPERATION;
822    }
823    return status;
824}
825
826status_t RadioService::ModuleClient::step(radio_direction_t direction, bool skipSubChannel)
827{
828    if (!PermissionCache::checkCallingPermission(RADIO_PERMISSION)) {
829        return PERMISSION_DENIED;
830    }
831    AutoMutex lock(mLock);
832    ALOGV("%s locked", __FUNCTION__);
833    status_t status;
834    if (mTuner != 0) {
835        status = (status_t)mTuner->step(direction, skipSubChannel);
836    } else {
837        status = INVALID_OPERATION;
838    }
839    return status;
840}
841
842status_t RadioService::ModuleClient::tune(uint32_t channel, uint32_t subChannel)
843{
844    if (!PermissionCache::checkCallingPermission(RADIO_PERMISSION)) {
845        return PERMISSION_DENIED;
846    }
847    AutoMutex lock(mLock);
848    ALOGV("%s locked", __FUNCTION__);
849    status_t status;
850    if (mTuner != 0) {
851        status = (status_t)mTuner->tune(channel, subChannel);
852    } else {
853        status = INVALID_OPERATION;
854    }
855    return status;
856}
857
858status_t RadioService::ModuleClient::cancel()
859{
860    if (!PermissionCache::checkCallingPermission(RADIO_PERMISSION)) {
861        return PERMISSION_DENIED;
862    }
863    AutoMutex lock(mLock);
864    ALOGV("%s locked", __FUNCTION__);
865    status_t status;
866    if (mTuner != 0) {
867        status = (status_t)mTuner->cancel();
868    } else {
869        status = INVALID_OPERATION;
870    }
871    return status;
872}
873
874status_t RadioService::ModuleClient::getProgramInformation(struct radio_program_info *info)
875{
876    if (!PermissionCache::checkCallingPermission(RADIO_PERMISSION)) {
877        return PERMISSION_DENIED;
878    }
879    AutoMutex lock(mLock);
880    ALOGV("%s locked", __FUNCTION__);
881    status_t status;
882    if (mTuner != NULL) {
883        status = (status_t)mTuner->getProgramInformation(info);
884    } else {
885        status = INVALID_OPERATION;
886    }
887
888    return status;
889}
890
891status_t RadioService::ModuleClient::hasControl(bool *hasControl)
892{
893    if (!PermissionCache::checkCallingPermission(RADIO_PERMISSION)) {
894        return PERMISSION_DENIED;
895    }
896    Mutex::Autolock lock(mLock);
897    ALOGV("%s locked", __FUNCTION__);
898    *hasControl = mTuner != 0;
899    return NO_ERROR;
900}
901
902void RadioService::ModuleClient::onCallbackEvent(const sp<IMemory>& eventMemory)
903{
904    if (eventMemory == 0 || eventMemory->pointer() == NULL) {
905        return;
906    }
907
908    sp<IRadioClient> client;
909    {
910        AutoMutex lock(mLock);
911        ALOGV("%s locked", __FUNCTION__);
912        radio_event_t *event = (radio_event_t *)eventMemory->pointer();
913        switch (event->type) {
914        case RADIO_EVENT_CONFIG:
915            mConfig.band = event->config.band;
916            event->config.region = mConfig.region;
917            break;
918        default:
919            break;
920        }
921
922        client = mClient;
923    }
924    if (client != 0) {
925        client->onEvent(eventMemory);
926    }
927}
928
929
930void RadioService::ModuleClient::binderDied(
931    const wp<IBinder> &who __unused) {
932    ALOGW("client binder died for client %p", this);
933    detach();
934}
935
936}; // namespace android
937