1 /*
2 * Copyright (c) 2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15 #include "intell_voice_trigger_adapter_impl.h"
16 #include "hdf_base.h"
17 #include "iproxy_broker.h"
18 #include "intell_voice_log.h"
19 #include "securec.h"
20 #include "scope_guard.h"
21 #include "memory_guard.h"
22
23 #undef HDF_LOG_TAG
24 #define HDF_LOG_TAG "TriggerAdapterImpl"
25
26 using namespace OHOS::HDI::IntelligentVoice::Trigger::V1_0;
27 using namespace OHOS::IntelligentVoice::Utils;
28
29 namespace OHOS {
30 namespace IntelligentVoice {
31 namespace Trigger {
IntellVoiceTriggerCallbackDevice(OHOS::sptr<IIntellVoiceTriggerCallback> callback)32 IntellVoiceTriggerCallbackDevice::IntellVoiceTriggerCallbackDevice(OHOS::sptr<IIntellVoiceTriggerCallback> callback)
33 : callback_(callback)
34 {}
35
~IntellVoiceTriggerCallbackDevice()36 IntellVoiceTriggerCallbackDevice::~IntellVoiceTriggerCallbackDevice()
37 {
38 callback_ = nullptr;
39 }
40
OnRecognitionHdiEvent(const IntellVoiceRecognitionEvent & event,int32_t cookie)41 void IntellVoiceTriggerCallbackDevice::OnRecognitionHdiEvent(const IntellVoiceRecognitionEvent &event, int32_t cookie)
42 {
43 if (callback_ == nullptr) {
44 INTELLIGENT_VOICE_LOGE("callback_ is nullptr");
45 return;
46 }
47 callback_->OnRecognitionHdiEvent(event, cookie);
48 }
49
IntellVoiceTriggerAdapterImpl(std::unique_ptr<ITrigger> adapter)50 IntellVoiceTriggerAdapterImpl::IntellVoiceTriggerAdapterImpl(std::unique_ptr<ITrigger> adapter)
51 : adapter_(std::move(adapter))
52 {}
53
~IntellVoiceTriggerAdapterImpl()54 IntellVoiceTriggerAdapterImpl::~IntellVoiceTriggerAdapterImpl()
55 {
56 adapter_ = nullptr;
57 }
58
GetProperties(IntellVoiceTriggerProperties & properties)59 int32_t IntellVoiceTriggerAdapterImpl::GetProperties(IntellVoiceTriggerProperties& properties)
60 {
61 return adapter_->GetProperties(properties);
62 }
63
LoadModel(const IntellVoiceTriggerModel & model,const sptr<IIntellVoiceTriggerCallback> & triggerCallback,int32_t cookie,int32_t & handle)64 int32_t IntellVoiceTriggerAdapterImpl::LoadModel(const IntellVoiceTriggerModel &model,
65 const sptr<IIntellVoiceTriggerCallback> &triggerCallback, int32_t cookie, int32_t &handle)
66 {
67 MemoryGuard memoryGuard;
68 std::shared_ptr<ITriggerCallback> cb = std::make_shared<IntellVoiceTriggerCallbackDevice>(triggerCallback);
69 if (cb == nullptr) {
70 INTELLIGENT_VOICE_LOGE("callback is nullptr");
71 return HDF_ERR_MALLOC_FAIL;
72 }
73
74 if (model.data == nullptr) {
75 INTELLIGENT_VOICE_LOGE("model data is nullptr");
76 return HDF_ERR_INVALID_PARAM;
77 }
78
79 ON_SCOPE_EXIT {
80 INTELLIGENT_VOICE_LOGI("close ashmem");
81 model.data->UnmapAshmem();
82 model.data->CloseAshmem();
83 };
84
85 std::vector<uint8_t> modelData;
86 if (GetModelDataFromAshmem(model.data, modelData) != static_cast<int32_t>(HDF_SUCCESS)) {
87 return HDF_ERR_INVALID_PARAM;
88 }
89
90 TriggerModel triggerModel(model.type, model.uid, modelData);
91 int32_t ret = adapter_->LoadIntellVoiceTriggerModel(triggerModel, cb, cookie, handle);
92 if (ret != 0) {
93 INTELLIGENT_VOICE_LOGE("failed to load model, ret:%{public}d", ret);
94 return ret;
95 }
96
97 RegisterDeathRecipient(handle, triggerCallback);
98 return ret;
99 }
100
UnloadModel(int32_t handle)101 int32_t IntellVoiceTriggerAdapterImpl::UnloadModel(int32_t handle)
102 {
103 MemoryGuard memoryGuard;
104 int32_t ret = adapter_->UnloadIntellVoiceTriggerModel(handle);
105 if (ret != 0) {
106 INTELLIGENT_VOICE_LOGE("failed to unload model");
107 return ret;
108 }
109
110 DeregisterDeathRecipient(handle);
111 return ret;
112 }
113
Start(int32_t handle)114 int32_t IntellVoiceTriggerAdapterImpl::Start(int32_t handle)
115 {
116 INTELLIGENT_VOICE_LOGE("Start");
117 MemoryGuard memoryGuard;
118 return adapter_->Start(handle);
119 }
120
Stop(int32_t handle)121 int32_t IntellVoiceTriggerAdapterImpl::Stop(int32_t handle)
122 {
123 MemoryGuard memoryGuard;
124 return adapter_->Stop(handle);
125 }
126
SetParams(const std::string & key,const std::string & value)127 int32_t IntellVoiceTriggerAdapterImpl::SetParams(const std::string &key, const std::string &value)
128 {
129 INTELLIGENT_VOICE_LOGI("enter");
130 MemoryGuard memoryGuard;
131 return adapter_->SetParams(key, value);
132 }
133
GetParams(const std::string & key,std::string & value)134 int32_t IntellVoiceTriggerAdapterImpl::GetParams(const std::string &key, std::string &value)
135 {
136 INTELLIGENT_VOICE_LOGI("enter");
137 MemoryGuard memoryGuard;
138 value = adapter_->GetParams(key);
139 return 0;
140 }
141
GetModelDataFromAshmem(sptr<Ashmem> ashmem,std::vector<uint8_t> & modelData)142 int32_t IntellVoiceTriggerAdapterImpl::GetModelDataFromAshmem(sptr<Ashmem> ashmem, std::vector<uint8_t> &modelData)
143 {
144 if (ashmem == nullptr) {
145 INTELLIGENT_VOICE_LOGE("ashmem is nullptr");
146 return HDF_ERR_INVALID_OBJECT;
147 }
148
149 uint32_t size = static_cast<uint32_t>(ashmem->GetAshmemSize());
150 if (size == 0) {
151 INTELLIGENT_VOICE_LOGE("size is zero");
152 return HDF_ERR_INVALID_PARAM;
153 }
154
155 if (!ashmem->MapReadOnlyAshmem()) {
156 INTELLIGENT_VOICE_LOGE("map ashmem failed");
157 return HDF_FAILURE;
158 }
159
160 const uint8_t *buffer = static_cast<const uint8_t *>(ashmem->ReadFromAshmem(size, 0));
161 if (buffer == nullptr) {
162 INTELLIGENT_VOICE_LOGE("read from ashmem failed");
163 return HDF_ERR_MALLOC_FAIL;
164 }
165
166 modelData.insert(modelData.begin(), buffer, buffer + size);
167 return HDF_SUCCESS;
168 }
169
RegisterDeathRecipient(int32_t handle,const sptr<IIntellVoiceTriggerCallback> & triggerCallback)170 bool IntellVoiceTriggerAdapterImpl::RegisterDeathRecipient(int32_t handle,
171 const sptr<IIntellVoiceTriggerCallback> &triggerCallback)
172 {
173 std::lock_guard<std::mutex> lock(mutex_);
174 INTELLIGENT_VOICE_LOGI("enter");
175 handleToCallbackMap_[handle] = triggerCallback;
176 sptr<IRemoteObject> object = OHOS::HDI::hdi_objcast<IIntellVoiceTriggerCallback>(triggerCallback);
177 if (object == nullptr) {
178 INTELLIGENT_VOICE_LOGE("object is nullptr");
179 return false;
180 }
181
182 auto it = callbackToHandleMap_.find(object.GetRefPtr());
183 if (it != callbackToHandleMap_.end()) {
184 it->second.insert(handle);
185 INTELLIGENT_VOICE_LOGI("callback already register, handle:%{public}d", handle);
186 return true;
187 }
188
189 sptr<IntellVoiceDeathRecipient> recipient = new (std::nothrow) IntellVoiceDeathRecipient(
190 std::bind(&IntellVoiceTriggerAdapterImpl::Clean, this, std::placeholders::_1), object.GetRefPtr());
191 if (recipient == nullptr) {
192 INTELLIGENT_VOICE_LOGE("create death recipient failed");
193 return false;
194 }
195
196 if (!object->AddDeathRecipient(recipient)) {
197 INTELLIGENT_VOICE_LOGE("add death recipient failed");
198 return false;
199 }
200
201 callbackToHandleMap_[object.GetRefPtr()].insert(handle);
202 deathRecipientMap_[object.GetRefPtr()] = recipient;
203 INTELLIGENT_VOICE_LOGI("register death recipient success");
204 return true;
205 }
206
DeregisterDeathRecipient(int32_t handle)207 void IntellVoiceTriggerAdapterImpl::DeregisterDeathRecipient(int32_t handle)
208 {
209 std::lock_guard<std::mutex> lock(mutex_);
210 auto callbackIter = handleToCallbackMap_.find(handle);
211 if (callbackIter == handleToCallbackMap_.end()) {
212 INTELLIGENT_VOICE_LOGE("failed to find callback");
213 return ;
214 }
215 sptr<IIntellVoiceTriggerCallback> callback = callbackIter->second;
216 handleToCallbackMap_.erase(callbackIter);
217
218 sptr<IRemoteObject> object = OHOS::HDI::hdi_objcast<IIntellVoiceTriggerCallback>(callback);
219 if (object == nullptr) {
220 INTELLIGENT_VOICE_LOGE("object is nullptr");
221 return;
222 }
223
224 auto handleSetIter = callbackToHandleMap_.find(object.GetRefPtr());
225 if (handleSetIter == callbackToHandleMap_.end()) {
226 INTELLIGENT_VOICE_LOGE("no handle set in callback, handle is: %{public}d", handle);
227 return;
228 }
229
230 auto handleIter = handleSetIter->second.find(handle);
231 if (handleIter == handleSetIter->second.end()) {
232 INTELLIGENT_VOICE_LOGE("no handle in handle set, handle is: %{public}d", handle);
233 return;
234 }
235
236 handleSetIter->second.erase(handleIter);
237 if (!handleSetIter->second.empty()) {
238 INTELLIGENT_VOICE_LOGI("handle set is not empty");
239 return;
240 }
241
242 if (deathRecipientMap_.count(object.GetRefPtr()) != 0) {
243 object->RemoveDeathRecipient(deathRecipientMap_[object.GetRefPtr()]);
244 deathRecipientMap_.erase(object.GetRefPtr());
245 }
246
247 callbackToHandleMap_.erase(object.GetRefPtr());
248 INTELLIGENT_VOICE_LOGI("handle set is empty, remove death recipient");
249 }
250
Clean(IRemoteObject * remote)251 void IntellVoiceTriggerAdapterImpl::Clean(IRemoteObject *remote)
252 {
253 std::lock_guard<std::mutex> lock(mutex_);
254 INTELLIGENT_VOICE_LOGI("enter");
255 if (remote == nullptr) {
256 INTELLIGENT_VOICE_LOGE("remote is nullptr");
257 return;
258 }
259
260 if (callbackToHandleMap_.count(remote) == 0) {
261 INTELLIGENT_VOICE_LOGE("no remote");
262 return;
263 }
264
265 MemoryGuard memoryGuard;
266 for (auto it = callbackToHandleMap_[remote].begin(); it != callbackToHandleMap_[remote].end(); ++it) {
267 INTELLIGENT_VOICE_LOGI("unload model, id is %{public}d", *it);
268 (void)adapter_->UnloadIntellVoiceTriggerModel(*it);
269 handleToCallbackMap_.erase(*it);
270 }
271
272 callbackToHandleMap_.erase(remote);
273 deathRecipientMap_.erase(remote);
274 }
275 } // namespace Trigger
276 } // namespace IntelligentVoice
277 } // namespace OHOS