1 /*
2  * Copyright (C) 2016 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 "EffectHalHidl"
18 //#define LOG_NDEBUG 0
19 
20 #include <common/all-versions/VersionUtils.h>
21 #include <cutils/native_handle.h>
22 #include <hwbinder/IPCThreadState.h>
23 #include <media/EffectsFactoryApi.h>
24 #include <utils/Log.h>
25 
26 #include <util/EffectUtils.h>
27 
28 #include "EffectBufferHalHidl.h"
29 #include "EffectHalHidl.h"
30 
31 using ::android::hardware::audio::common::utils::EnumBitfield;
32 using ::android::hardware::audio::effect::CPP_VERSION::implementation::EffectUtils;
33 using ::android::hardware::hidl_vec;
34 using ::android::hardware::MQDescriptorSync;
35 using ::android::hardware::Return;
36 
37 namespace android {
38 namespace effect {
39 namespace CPP_VERSION {
40 
41 using namespace ::android::hardware::audio::common::CPP_VERSION;
42 using namespace ::android::hardware::audio::effect::CPP_VERSION;
43 
EffectHalHidl(const sp<IEffect> & effect,uint64_t effectId)44 EffectHalHidl::EffectHalHidl(const sp<IEffect>& effect, uint64_t effectId)
45         : mEffect(effect), mEffectId(effectId), mBuffersChanged(true), mEfGroup(nullptr) {
46     effect_descriptor_t halDescriptor{};
47     if (EffectHalHidl::getDescriptor(&halDescriptor) == NO_ERROR) {
48         mIsInput = (halDescriptor.flags & EFFECT_FLAG_TYPE_PRE_PROC) == EFFECT_FLAG_TYPE_PRE_PROC;
49     }
50 }
51 
~EffectHalHidl()52 EffectHalHidl::~EffectHalHidl() {
53     if (mEffect != 0) {
54         close();
55         mEffect.clear();
56         hardware::IPCThreadState::self()->flushCommands();
57     }
58     if (mEfGroup) {
59         EventFlag::deleteEventFlag(&mEfGroup);
60     }
61 }
62 
63 // static
analyzeResult(const Result & result)64 status_t EffectHalHidl::analyzeResult(const Result& result) {
65     switch (result) {
66         case Result::OK: return OK;
67         case Result::INVALID_ARGUMENTS: return BAD_VALUE;
68         case Result::INVALID_STATE: return NOT_ENOUGH_DATA;
69         case Result::NOT_INITIALIZED: return NO_INIT;
70         case Result::NOT_SUPPORTED: return INVALID_OPERATION;
71         case Result::RESULT_TOO_BIG: return NO_MEMORY;
72         default: return NO_INIT;
73     }
74 }
75 
setInBuffer(const sp<EffectBufferHalInterface> & buffer)76 status_t EffectHalHidl::setInBuffer(const sp<EffectBufferHalInterface>& buffer) {
77     if (!mBuffersChanged) {
78         if (buffer.get() == nullptr || mInBuffer.get() == nullptr) {
79             mBuffersChanged = buffer.get() != mInBuffer.get();
80         } else {
81             mBuffersChanged = buffer->audioBuffer() != mInBuffer->audioBuffer();
82         }
83     }
84     mInBuffer = buffer;
85     return OK;
86 }
87 
setOutBuffer(const sp<EffectBufferHalInterface> & buffer)88 status_t EffectHalHidl::setOutBuffer(const sp<EffectBufferHalInterface>& buffer) {
89     if (!mBuffersChanged) {
90         if (buffer.get() == nullptr || mOutBuffer.get() == nullptr) {
91             mBuffersChanged = buffer.get() != mOutBuffer.get();
92         } else {
93             mBuffersChanged = buffer->audioBuffer() != mOutBuffer->audioBuffer();
94         }
95     }
96     mOutBuffer = buffer;
97     return OK;
98 }
99 
process()100 status_t EffectHalHidl::process() {
101     return processImpl(static_cast<uint32_t>(MessageQueueFlagBits::REQUEST_PROCESS));
102 }
103 
processReverse()104 status_t EffectHalHidl::processReverse() {
105     return processImpl(static_cast<uint32_t>(MessageQueueFlagBits::REQUEST_PROCESS_REVERSE));
106 }
107 
prepareForProcessing()108 status_t EffectHalHidl::prepareForProcessing() {
109     std::unique_ptr<StatusMQ> tempStatusMQ;
110     Result retval;
111     Return<void> ret = mEffect->prepareForProcessing(
112             [&](Result r, const MQDescriptorSync<Result>& statusMQ) {
113                 retval = r;
114                 if (retval == Result::OK) {
115                     tempStatusMQ.reset(new StatusMQ(statusMQ));
116                     if (tempStatusMQ->isValid() && tempStatusMQ->getEventFlagWord()) {
117                         EventFlag::createEventFlag(tempStatusMQ->getEventFlagWord(), &mEfGroup);
118                     }
119                 }
120             });
121     if (!ret.isOk() || retval != Result::OK) {
122         return ret.isOk() ? analyzeResult(retval) : FAILED_TRANSACTION;
123     }
124     if (!tempStatusMQ || !tempStatusMQ->isValid() || !mEfGroup) {
125         ALOGE_IF(!tempStatusMQ, "Failed to obtain status message queue for effects");
126         ALOGE_IF(tempStatusMQ && !tempStatusMQ->isValid(),
127                 "Status message queue for effects is invalid");
128         ALOGE_IF(!mEfGroup, "Event flag creation for effects failed");
129         return NO_INIT;
130     }
131     mStatusMQ = std::move(tempStatusMQ);
132     return OK;
133 }
134 
needToResetBuffers()135 bool EffectHalHidl::needToResetBuffers() {
136     if (mBuffersChanged) return true;
137     bool inBufferFrameCountUpdated = mInBuffer->checkFrameCountChange();
138     bool outBufferFrameCountUpdated = mOutBuffer->checkFrameCountChange();
139     return inBufferFrameCountUpdated || outBufferFrameCountUpdated;
140 }
141 
processImpl(uint32_t mqFlag)142 status_t EffectHalHidl::processImpl(uint32_t mqFlag) {
143     if (mEffect == 0 || mInBuffer == 0 || mOutBuffer == 0) return NO_INIT;
144     status_t status;
145     if (!mStatusMQ && (status = prepareForProcessing()) != OK) {
146         return status;
147     }
148     if (needToResetBuffers() && (status = setProcessBuffers()) != OK) {
149         return status;
150     }
151     // The data is already in the buffers, just need to flush it and wake up the server side.
152     std::atomic_thread_fence(std::memory_order_release);
153     mEfGroup->wake(mqFlag);
154     uint32_t efState = 0;
155 retry:
156     status_t ret = mEfGroup->wait(
157             static_cast<uint32_t>(MessageQueueFlagBits::DONE_PROCESSING), &efState);
158     if (efState & static_cast<uint32_t>(MessageQueueFlagBits::DONE_PROCESSING)) {
159         Result retval = Result::NOT_INITIALIZED;
160         mStatusMQ->read(&retval);
161         if (retval == Result::OK || retval == Result::INVALID_STATE) {
162             // Sync back the changed contents of the buffer.
163             std::atomic_thread_fence(std::memory_order_acquire);
164         }
165         return analyzeResult(retval);
166     }
167     if (ret == -EAGAIN || ret == -EINTR) {
168         // Spurious wakeup. This normally retries no more than once.
169         goto retry;
170     }
171     return ret;
172 }
173 
setProcessBuffers()174 status_t EffectHalHidl::setProcessBuffers() {
175     Return<Result> ret = mEffect->setProcessBuffers(
176             static_cast<EffectBufferHalHidl*>(mInBuffer.get())->hidlBuffer(),
177             static_cast<EffectBufferHalHidl*>(mOutBuffer.get())->hidlBuffer());
178     if (ret.isOk() && ret == Result::OK) {
179         mBuffersChanged = false;
180         return OK;
181     }
182     return ret.isOk() ? analyzeResult(ret) : FAILED_TRANSACTION;
183 }
184 
command(uint32_t cmdCode,uint32_t cmdSize,void * pCmdData,uint32_t * replySize,void * pReplyData)185 status_t EffectHalHidl::command(uint32_t cmdCode, uint32_t cmdSize, void *pCmdData,
186         uint32_t *replySize, void *pReplyData) {
187     if (mEffect == 0) return NO_INIT;
188 
189     // Special cases.
190     if (cmdCode == EFFECT_CMD_SET_CONFIG || cmdCode == EFFECT_CMD_SET_CONFIG_REVERSE) {
191         return setConfigImpl(cmdCode, cmdSize, pCmdData, replySize, pReplyData);
192     } else if (cmdCode == EFFECT_CMD_GET_CONFIG || cmdCode == EFFECT_CMD_GET_CONFIG_REVERSE) {
193         return getConfigImpl(cmdCode, replySize, pReplyData);
194     }
195 
196     // Common case.
197     hidl_vec<uint8_t> hidlData;
198     if (pCmdData != nullptr && cmdSize > 0) {
199         hidlData.setToExternal(reinterpret_cast<uint8_t*>(pCmdData), cmdSize);
200     }
201     status_t status;
202     uint32_t replySizeStub = 0;
203     if (replySize == nullptr || pReplyData == nullptr) replySize = &replySizeStub;
204     Return<void> ret = mEffect->command(cmdCode, hidlData, *replySize,
205             [&](int32_t s, const hidl_vec<uint8_t>& result) {
206                 status = s;
207                 if (status == 0) {
208                     if (*replySize > result.size()) *replySize = result.size();
209                     if (pReplyData != nullptr && *replySize > 0) {
210                         memcpy(pReplyData, &result[0], *replySize);
211                     }
212                 }
213             });
214     return ret.isOk() ? status : FAILED_TRANSACTION;
215 }
216 
getDescriptor(effect_descriptor_t * pDescriptor)217 status_t EffectHalHidl::getDescriptor(effect_descriptor_t *pDescriptor) {
218     if (mEffect == 0) return NO_INIT;
219     Result retval = Result::NOT_INITIALIZED;
220     Return<void> ret = mEffect->getDescriptor(
221             [&](Result r, const EffectDescriptor& result) {
222                 retval = r;
223                 if (retval == Result::OK) {
224                     EffectUtils::effectDescriptorToHal(result, pDescriptor);
225                 }
226             });
227     return ret.isOk() ? analyzeResult(retval) : FAILED_TRANSACTION;
228 }
229 
close()230 status_t EffectHalHidl::close() {
231     if (mEffect == 0) return NO_INIT;
232     Return<Result> ret = mEffect->close();
233     return ret.isOk() ? analyzeResult(ret) : FAILED_TRANSACTION;
234 }
235 
dump(int fd)236 status_t EffectHalHidl::dump(int fd) {
237     if (mEffect == 0) return NO_INIT;
238     native_handle_t* hidlHandle = native_handle_create(1, 0);
239     hidlHandle->data[0] = fd;
240     Return<void> ret = mEffect->debug(hidlHandle, {} /* options */);
241     native_handle_delete(hidlHandle);
242 
243     // TODO(b/111997867, b/177271958)  Workaround - remove when fixed.
244     // A Binder transmitted fd may not close immediately due to a race condition b/111997867
245     // when the remote binder thread removes the last refcount to the fd blocks in the
246     // kernel for binder activity. We send a Binder ping() command to unblock the thread
247     // and complete the fd close / release.
248     //
249     // See DeviceHalHidl::dump(), EffectHalHidl::dump(), StreamHalHidl::dump(),
250     //     EffectsFactoryHalHidl::dumpEffects().
251 
252     (void)mEffect->ping(); // synchronous Binder call
253 
254     return ret.isOk() ? OK : FAILED_TRANSACTION;
255 }
256 
getConfigImpl(uint32_t cmdCode,uint32_t * replySize,void * pReplyData)257 status_t EffectHalHidl::getConfigImpl(
258         uint32_t cmdCode, uint32_t *replySize, void *pReplyData) {
259     if (replySize == NULL || *replySize != sizeof(effect_config_t) || pReplyData == NULL) {
260         return BAD_VALUE;
261     }
262     status_t result = FAILED_TRANSACTION;
263     Return<void> ret;
264     if (cmdCode == EFFECT_CMD_GET_CONFIG) {
265         ret = mEffect->getConfig([&] (Result r, const EffectConfig &hidlConfig) {
266             result = analyzeResult(r);
267             if (r == Result::OK) {
268                 EffectUtils::effectConfigToHal(
269                         hidlConfig, static_cast<effect_config_t*>(pReplyData));
270             }
271         });
272     } else {
273         ret = mEffect->getConfigReverse([&] (Result r, const EffectConfig &hidlConfig) {
274             result = analyzeResult(r);
275             if (r == Result::OK) {
276                 EffectUtils::effectConfigToHal(
277                         hidlConfig, static_cast<effect_config_t*>(pReplyData));
278             }
279         });
280     }
281     if (!ret.isOk()) {
282         result = FAILED_TRANSACTION;
283     }
284     return result;
285 }
286 
setConfigImpl(uint32_t cmdCode,uint32_t cmdSize,void * pCmdData,uint32_t * replySize,void * pReplyData)287 status_t EffectHalHidl::setConfigImpl(
288         uint32_t cmdCode, uint32_t cmdSize, void *pCmdData, uint32_t *replySize, void *pReplyData) {
289     if (pCmdData == NULL || cmdSize != sizeof(effect_config_t) ||
290             replySize == NULL || *replySize != sizeof(int32_t) || pReplyData == NULL) {
291         return BAD_VALUE;
292     }
293     const effect_config_t *halConfig = static_cast<effect_config_t*>(pCmdData);
294     if (halConfig->inputCfg.bufferProvider.getBuffer != NULL ||
295             halConfig->inputCfg.bufferProvider.releaseBuffer != NULL ||
296             halConfig->outputCfg.bufferProvider.getBuffer != NULL ||
297             halConfig->outputCfg.bufferProvider.releaseBuffer != NULL) {
298         ALOGE("Buffer provider callbacks are not supported");
299     }
300     EffectConfig hidlConfig;
301     EffectUtils::effectConfigFromHal(*halConfig, mIsInput, &hidlConfig);
302     Return<Result> ret = cmdCode == EFFECT_CMD_SET_CONFIG ?
303             mEffect->setConfig(hidlConfig, nullptr, nullptr) :
304             mEffect->setConfigReverse(hidlConfig, nullptr, nullptr);
305     status_t result = FAILED_TRANSACTION;
306     if (ret.isOk()) {
307         result = analyzeResult(ret);
308         *static_cast<int32_t*>(pReplyData) = result;
309     }
310     return result;
311 }
312 
313 } // namespace CPP_VERSION
314 } // namespace effect
315 } // namespace android
316