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