1 /* 2 * Copyright (C) 2020 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 #ifndef ST_HAL_LPMA_HANDLER_H_ 18 #define ST_HAL_LPMA_HANDLER_H_ 19 20 #include <condition_variable> 21 #include <cstdio> 22 #include <functional> 23 #include <mutex> 24 #include <thread> 25 26 #include "chre_host/log.h" 27 28 #include <android/hardware/soundtrigger/2.0/ISoundTriggerHw.h> 29 #include <hardware_legacy/power.h> 30 31 using android::hardware::hidl_death_recipient; 32 using android::hardware::Return; 33 using android::hardware::soundtrigger::V2_0::ISoundTriggerHw; 34 using android::hardware::soundtrigger::V2_0::SoundModelHandle; 35 using android::hardware::soundtrigger::V2_0::SoundModelType; 36 using android::hidl::base::V1_0::IBase; 37 38 namespace android { 39 namespace chre { 40 41 /** 42 * Handles interactions with the SoundTrigger (ST) HAL, to issue configuration 43 * requests for the always-on audio hardware to enable Low Power Microphone 44 * Access (LPMA) in CHRE. Typically, this class is used when the CHRE audio 45 * implementation for a given system requires notifying the ST HAL when audio 46 * is requested/released within CHRE 47 */ 48 class StHalLpmaHandler { 49 public: 50 //! Class to handle when a connected ST HAL service dies 51 class StHalDeathRecipient : public hidl_death_recipient { 52 public: 53 StHalDeathRecipient() = delete; StHalDeathRecipient(std::function<void ()> cb)54 explicit StHalDeathRecipient(std::function<void()> cb) : mCallback(cb) {} 55 56 /** 57 * Callback that is called when a connected service dies. It mainly 58 * resets the LPMA Enabled flag, and unblocks the LPMA processing thread. 59 * It is to be used in conjunction with linkToDeath(), which we do 60 * in checkConnectionToStHalServiceLocked(). 61 */ serviceDied(uint64_t,const wp<IBase> &)62 virtual void serviceDied(uint64_t /* cookie */, 63 const wp<IBase> & /* who */) override { 64 mCallback(); 65 } 66 67 private: 68 std::function<void()> mCallback; 69 }; 70 71 StHalLpmaHandler() = delete; 72 73 explicit StHalLpmaHandler(bool allowed); 74 ~StHalLpmaHandler()75 ~StHalLpmaHandler() { 76 if (mThread.has_value()) { 77 // TODO: Change this to join after adding proper handler 78 mThread->detach(); 79 } 80 } 81 82 /** 83 * If LPMA is enabled, starts a worker thread to load/unload models. 84 */ 85 void init(); 86 87 /** 88 * Sets the target state for LPMA to be enabled. This triggers another thread 89 * to perform the async operation of enabling or disabling the LPMA use case. 90 * 91 * @param enabled Whether LPMA is to be enabled or disabled. 92 */ 93 void enable(bool enabled); 94 95 /** 96 * Loads the LPMA use case via the SoundTrigger HAL HIDL service. 97 * 98 * @return true if LPMA was enabled successfully, false otherwise. 99 */ 100 bool load(); 101 102 /** 103 * Unloads the LPMA use case via the SoundTrigger HAL HIDL service. This 104 * function does not indicate success/failure as it is expected that even in 105 * the event of a failure to unload, the use case will be unloaded. As long as 106 * the sound trigger HAL received the request we can be assured that the use 107 * case will be unloaded (even if it means reseting the codec or otherwise). 108 */ 109 void unload(); 110 111 /** 112 * Entry point for the thread that loads/unloads sound models from the 113 * ST HAL 114 */ 115 void StHalLpmaHandlerThreadEntry(); 116 117 private: 118 const bool mIsLpmaAllowed; 119 bool mCurrentLpmaEnabled; 120 bool mTargetLpmaEnabled; 121 bool mCondVarPredicate; 122 SoundModelHandle mLpmaHandle = 0; 123 124 int mRetryCount; 125 useconds_t mRetryDelay; 126 127 std::optional<std::thread> mThread; 128 std::mutex mMutex; 129 std::condition_variable mCondVar; 130 131 sp<StHalDeathRecipient> mDeathRecipient; 132 sp<ISoundTriggerHw> mStHalService; 133 134 /** 135 * Checks for a valid connection to the ST HAL service, reconnects if not 136 * already connected. This method should only be invoked after acquiring the 137 * class mutex has been locked. 138 */ 139 void checkConnectionToStHalServiceLocked(); 140 141 /** 142 * Invoked by the HAL service death callback. see 143 * StHalDeathRecipient::ServiceDied() 144 */ 145 void onStHalServiceDeath(); 146 147 /** 148 * This function blocks on a condition variable and when notified, based 149 * on its current state and as notified by enable(), performs a load or 150 * unload. The function also resets the delay and retry counts if the current 151 * and next states match 152 * 153 * @return true if the state update succeeded, and we don't need to retry with 154 * a delay 155 */ 156 bool waitOnStHalRequestAndProcess(); 157 158 /** 159 * Delay retrying a load if a state update failed 160 */ 161 void delay(); 162 }; 163 164 } // namespace chre 165 } // namespace android 166 167 #endif // ST_HAL_LPMA_HANDLER_H_ 168