1 /* 2 * Copyright (C) 2022 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 #pragma once 18 19 #include <condition_variable> 20 #include <memory> 21 #include <mutex> 22 23 #include <android-base/properties.h> 24 #include <android/binder_auto_utils.h> 25 #include <android/binder_manager.h> 26 #include <android/binder_process.h> 27 28 #include <android-base/logging.h> 29 30 class AudioHalBinderServiceUtil { 31 public: connectToService(const std::string & serviceName)32 ndk::SpAIBinder connectToService(const std::string& serviceName) { 33 mServiceName = serviceName; 34 mBinder = ndk::SpAIBinder(AServiceManager_waitForService(serviceName.c_str())); 35 if (mBinder == nullptr) { 36 LOG(ERROR) << "Failed to get service " << serviceName; 37 } else { 38 LOG(DEBUG) << "Succeeded to get service " << serviceName; 39 } 40 return mBinder; 41 } 42 43 ndk::SpAIBinder restartService( 44 std::chrono::milliseconds timeoutMs = std::chrono::milliseconds(3000)) { 45 if (!stopService(timeoutMs)) { 46 return {}; 47 } 48 return connectToService(mServiceName); 49 } 50 51 private: 52 class AidlDeathRecipient { 53 public: AidlDeathRecipient(const ndk::SpAIBinder & binder)54 explicit AidlDeathRecipient(const ndk::SpAIBinder& binder) 55 : binder(binder), recipient(AIBinder_DeathRecipient_new(&binderDiedCallbackAidl)) {} 56 linkToDeath()57 binder_status_t linkToDeath() { 58 return AIBinder_linkToDeath(binder.get(), recipient.get(), this); 59 } 60 waitForFired(std::chrono::milliseconds timeoutMs)61 bool waitForFired(std::chrono::milliseconds timeoutMs) { 62 std::unique_lock<std::mutex> lock(mutex); 63 return condition.wait_for(lock, timeoutMs, [this]() { return fired; }); 64 } 65 66 private: 67 const ndk::SpAIBinder binder; 68 const ndk::ScopedAIBinder_DeathRecipient recipient; 69 std::mutex mutex; 70 std::condition_variable condition; 71 bool fired = false; 72 binderDied()73 void binderDied() { 74 std::unique_lock<std::mutex> lock(mutex); 75 fired = true; 76 condition.notify_one(); 77 }; 78 binderDiedCallbackAidl(void * cookie)79 static void binderDiedCallbackAidl(void* cookie) { 80 AidlDeathRecipient* self = static_cast<AidlDeathRecipient*>(cookie); 81 self->binderDied(); 82 } 83 }; 84 stopService(std::chrono::milliseconds timeoutMs)85 bool stopService(std::chrono::milliseconds timeoutMs) { 86 AidlDeathRecipient deathHandler(mBinder); 87 if (STATUS_OK != deathHandler.linkToDeath()) { 88 LOG(ERROR) << "linkToDeath failed"; 89 return false; 90 } 91 if (!android::base::SetProperty("sys.audio.restart.hal", "1")) { 92 LOG(ERROR) << "SetProperty failed"; 93 return false; 94 } 95 if (!deathHandler.waitForFired(timeoutMs)) { 96 LOG(ERROR) << "Timeout wait for death of " << mServiceName; 97 return false; 98 } 99 return true; 100 } 101 102 std::string mServiceName; 103 ndk::SpAIBinder mBinder; 104 }; 105