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 <hardware_legacy/power.h>
21 #include <condition_variable>
22 #include <cstdio>
23 #include <functional>
24 #include <mutex>
25 #include <thread>
26 
27 #include "chre_host/log.h"
28 
29 #ifdef CHRE_ST_LPMA_HANDLER_AIDL
30 #include <aidl/android/hardware/soundtrigger3/ISoundTriggerHw.h>
31 #include <android/binder_manager.h>
32 #include <android/binder_process.h>
33 #else
34 #include <android/hardware/soundtrigger/2.0/ISoundTriggerHw.h>
35 #endif  // CHRE_ST_LPMA_HANDLER_AIDL
36 
37 #ifdef CHRE_ST_LPMA_HANDLER_AIDL
38 using aidl::android::hardware::soundtrigger3::ISoundTriggerHw;
39 #else
40 using android::hardware::hidl_death_recipient;
41 using android::hardware::Return;
42 using android::hardware::soundtrigger::V2_0::ISoundTriggerHw;
43 using android::hardware::soundtrigger::V2_0::SoundModelHandle;
44 using android::hardware::soundtrigger::V2_0::SoundModelType;
45 using android::hidl::base::V1_0::IBase;
46 #endif  // CHRE_ST_LPMA_HANDLER_AIDL
47 
48 namespace android {
49 namespace chre {
50 
51 /**
52  * Handles interactions with the SoundTrigger (ST) HAL, to issue configuration
53  * requests for the always-on audio hardware to enable Low Power Microphone
54  * Access (LPMA) in CHRE. Typically, this class is used when the CHRE audio
55  * implementation for a given system requires notifying the ST HAL when audio
56  * is requested/released within CHRE
57  */
58 class StHalLpmaHandler {
59  public:
60   StHalLpmaHandler() = delete;
61   explicit StHalLpmaHandler(bool allowed);
62 
63   ~StHalLpmaHandler();
64 
65   /**
66    * If LPMA is enabled, starts a worker thread to load/unload models.
67    */
68   void init();
69 
70   /**
71    * Sets the target state for LPMA to be enabled. This triggers another thread
72    * to perform the async operation of enabling or disabling the LPMA use case.
73    *
74    * @param enabled Whether LPMA is to be enabled or disabled.
75    */
76   void enable(bool enabled);
77 
78  private:
79   const bool mIsLpmaAllowed;
80   bool mCurrentLpmaEnabled;
81   bool mTargetLpmaEnabled;
82   bool mCondVarPredicate;
83   bool mStThreadShouldExit = false;
84 
85   int mRetryCount;
86   useconds_t mRetryDelay;
87 
88   std::optional<std::thread> mThread;
89   std::mutex mMutex;
90   std::condition_variable mCondVar;
91 
92 #ifdef CHRE_ST_LPMA_HANDLER_AIDL
93   int32_t mLpmaHandle = 0;
94   std::shared_ptr<ISoundTriggerHw> mStHalService;
95 #else
96   //! Class to handle when a connected ST HAL service dies
97   class StHalDeathRecipient : public hidl_death_recipient {
98    public:
99     StHalDeathRecipient() = delete;
StHalDeathRecipient(std::function<void ()> cb)100     explicit StHalDeathRecipient(std::function<void()> cb) : mCallback(cb) {}
101 
102     /**
103      * Callback that is called when a connected service dies. It mainly
104      * resets the LPMA Enabled flag, and unblocks the LPMA processing thread.
105      * It is to be used in conjunction with linkToDeath(), which we do
106      * in checkConnectionToStHalServiceLocked().
107      */
serviceDied(uint64_t,const wp<IBase> &)108     void serviceDied(uint64_t /* cookie */,
109                      const wp<IBase> & /* who */) override {
110       mCallback();
111     }
112 
113    private:
114     std::function<void()> mCallback;
115   };
116   SoundModelHandle mLpmaHandle = 0;
117   sp<StHalDeathRecipient> mDeathRecipient;
118   sp<ISoundTriggerHw> mStHalService;
119 #endif  // CHRE_ST_LPMA_HANDLER_AIDL
120 
121   /**
122    * Loads the LPMA use case via the SoundTrigger HAL HIDL service.
123    *
124    * @return true if LPMA was enabled successfully, false otherwise.
125    */
126   bool load();
127 
128   /**
129    * Unloads the LPMA use case via the SoundTrigger HAL HIDL service. This
130    * function does not indicate success/failure as it is expected that even in
131    * the event of a failure to unload, the use case will be unloaded. As long as
132    * the sound trigger HAL received the request we can be assured that the use
133    * case will be unloaded (even if it means reseting the codec or otherwise).
134    */
135   void unload();
136 
137   /**
138    * If CHRE_LPMA_REQUEST_START_RECOGNITION is defined, calls startRecognition()
139    * on the currently loaded model. No-op otherwise.
140    *
141    * @return true on success
142    */
143   bool start();
144 
145   //! Invokes stopRecognition() on the currently loaded model
146   /**
147    * If CHRE_LPMA_REQUEST_START_RECOGNITION is defined, calls stopRecognition()
148    * on the currently loaded model. No-op otherwise.
149    *
150    * @return true on success
151    */
152   void stop();
153 
154   // Convenience methods
155   bool loadAndStart();
156   void stopAndUnload();
157 
158   /**
159    * Entry point for the thread that loads/unloads sound models from the
160    * ST HAL
161    */
162   void stHalLpmaHandlerThreadEntry();
163 
164   /**
165    * Checks for a valid connection to the ST HAL service, reconnects if not
166    * already connected. This method should only be invoked after acquiring the
167    * class mutex has been locked.
168    */
169   void checkConnectionToStHalServiceLocked();
170 
171   /**
172    * Invoked by the HAL service death callback. see
173    * StHalDeathRecipient::ServiceDied()
174    */
175   void onStHalServiceDeath();
176 
177   /**
178    * Invoke Hal to load or unload LPMA depending on the status of
179    * mTargetLpmaEnabled and mCurrentLpmaEnabled
180    *
181    * @param locked lock that holds the mutex that guards mTargetLpmaEnabled
182    */
183   void stHalRequestAndProcessLocked(std::unique_lock<std::mutex> const &locked);
184 };
185 }  // namespace chre
186 }  // namespace android
187 
188 #endif  // ST_HAL_LPMA_HANDLER_H_
189