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(static_cast<OHOS::HDI::IntelligentVoice::Trigger::V1_2::IntellVoiceTriggerModelType>(
91         model.type), model.uid, modelData);
92     int32_t ret = adapter_->LoadIntellVoiceTriggerModel(triggerModel, cb, cookie, handle);
93     if (ret != 0) {
94         INTELLIGENT_VOICE_LOGE("failed to load model, ret:%{public}d", ret);
95         return ret;
96     }
97 
98     RegisterDeathRecipient(handle, triggerCallback);
99     return ret;
100 }
101 
UnloadModel(int32_t handle)102 int32_t IntellVoiceTriggerAdapterImpl::UnloadModel(int32_t handle)
103 {
104     MemoryGuard memoryGuard;
105     int32_t ret = adapter_->UnloadIntellVoiceTriggerModel(handle);
106     if (ret != 0) {
107         INTELLIGENT_VOICE_LOGE("failed to unload model");
108         return ret;
109     }
110 
111     DeregisterDeathRecipient(handle);
112     return ret;
113 }
114 
Start(int32_t handle)115 int32_t IntellVoiceTriggerAdapterImpl::Start(int32_t handle)
116 {
117     INTELLIGENT_VOICE_LOGE("Start");
118     MemoryGuard memoryGuard;
119     return adapter_->Start(handle);
120 }
121 
Stop(int32_t handle)122 int32_t IntellVoiceTriggerAdapterImpl::Stop(int32_t handle)
123 {
124     MemoryGuard memoryGuard;
125     return adapter_->Stop(handle);
126 }
127 
SetParams(const std::string & key,const std::string & value)128 int32_t IntellVoiceTriggerAdapterImpl::SetParams(const std::string &key, const std::string &value)
129 {
130     INTELLIGENT_VOICE_LOGI("enter");
131     MemoryGuard memoryGuard;
132     return adapter_->SetParams(key, value);
133 }
134 
GetParams(const std::string & key,std::string & value)135 int32_t IntellVoiceTriggerAdapterImpl::GetParams(const std::string &key, std::string &value)
136 {
137     INTELLIGENT_VOICE_LOGI("enter");
138     MemoryGuard memoryGuard;
139     value = adapter_->GetParams(key);
140     return 0;
141 }
142 
GetModelDataFromAshmem(sptr<Ashmem> ashmem,std::vector<uint8_t> & modelData)143 int32_t IntellVoiceTriggerAdapterImpl::GetModelDataFromAshmem(sptr<Ashmem> ashmem, std::vector<uint8_t> &modelData)
144 {
145     if (ashmem == nullptr) {
146         INTELLIGENT_VOICE_LOGE("ashmem is nullptr");
147         return HDF_ERR_INVALID_OBJECT;
148     }
149 
150     uint32_t size = static_cast<uint32_t>(ashmem->GetAshmemSize());
151     if (size == 0) {
152         INTELLIGENT_VOICE_LOGE("size is zero");
153         return HDF_ERR_INVALID_PARAM;
154     }
155 
156     if (!ashmem->MapReadOnlyAshmem()) {
157         INTELLIGENT_VOICE_LOGE("map ashmem failed");
158         return HDF_FAILURE;
159     }
160 
161     const uint8_t *buffer = static_cast<const uint8_t *>(ashmem->ReadFromAshmem(size, 0));
162     if (buffer == nullptr) {
163         INTELLIGENT_VOICE_LOGE("read from ashmem failed");
164         return HDF_ERR_MALLOC_FAIL;
165     }
166 
167     modelData.insert(modelData.begin(), buffer, buffer + size);
168     return HDF_SUCCESS;
169 }
170 
RegisterDeathRecipient(int32_t handle,const sptr<IIntellVoiceTriggerCallback> & triggerCallback)171 bool IntellVoiceTriggerAdapterImpl::RegisterDeathRecipient(int32_t handle,
172     const sptr<IIntellVoiceTriggerCallback> &triggerCallback)
173 {
174     std::lock_guard<std::mutex> lock(mutex_);
175     INTELLIGENT_VOICE_LOGI("enter");
176     handleToCallbackMap_[handle] = triggerCallback;
177     sptr<IRemoteObject> object = OHOS::HDI::hdi_objcast<IIntellVoiceTriggerCallback>(triggerCallback);
178     if (object == nullptr) {
179         INTELLIGENT_VOICE_LOGE("object is nullptr");
180         return false;
181     }
182 
183     auto it = callbackToHandleMap_.find(object.GetRefPtr());
184     if (it != callbackToHandleMap_.end()) {
185         it->second.insert(handle);
186         INTELLIGENT_VOICE_LOGI("callback already register, handle:%{public}d", handle);
187         return true;
188     }
189 
190     sptr<IntellVoiceDeathRecipient> recipient = new (std::nothrow) IntellVoiceDeathRecipient(
191         std::bind(&IntellVoiceTriggerAdapterImpl::Clean, this, std::placeholders::_1), object.GetRefPtr());
192     if (recipient == nullptr) {
193         INTELLIGENT_VOICE_LOGE("create death recipient failed");
194         return false;
195     }
196 
197     if (!object->AddDeathRecipient(recipient)) {
198         INTELLIGENT_VOICE_LOGE("add death recipient failed");
199         return false;
200     }
201 
202     callbackToHandleMap_[object.GetRefPtr()].insert(handle);
203     deathRecipientMap_[object.GetRefPtr()] = recipient;
204     INTELLIGENT_VOICE_LOGI("register death recipient success");
205     return true;
206 }
207 
DeregisterDeathRecipient(int32_t handle)208 void IntellVoiceTriggerAdapterImpl::DeregisterDeathRecipient(int32_t handle)
209 {
210     std::lock_guard<std::mutex> lock(mutex_);
211     auto callbackIter = handleToCallbackMap_.find(handle);
212     if (callbackIter == handleToCallbackMap_.end()) {
213         INTELLIGENT_VOICE_LOGE("failed to find callback");
214         return ;
215     }
216     sptr<IIntellVoiceTriggerCallback> callback = callbackIter->second;
217     handleToCallbackMap_.erase(callbackIter);
218 
219     sptr<IRemoteObject> object = OHOS::HDI::hdi_objcast<IIntellVoiceTriggerCallback>(callback);
220     if (object == nullptr) {
221         INTELLIGENT_VOICE_LOGE("object is nullptr");
222         return;
223     }
224 
225     auto handleSetIter = callbackToHandleMap_.find(object.GetRefPtr());
226     if (handleSetIter == callbackToHandleMap_.end()) {
227         INTELLIGENT_VOICE_LOGE("no handle set in callback, handle is: %{public}d", handle);
228         return;
229     }
230 
231     auto handleIter = handleSetIter->second.find(handle);
232     if (handleIter == handleSetIter->second.end()) {
233         INTELLIGENT_VOICE_LOGE("no handle in handle set, handle is: %{public}d", handle);
234         return;
235     }
236 
237     handleSetIter->second.erase(handleIter);
238     if (!handleSetIter->second.empty()) {
239         INTELLIGENT_VOICE_LOGI("handle set is not empty");
240         return;
241     }
242 
243     if (deathRecipientMap_.count(object.GetRefPtr()) != 0) {
244         object->RemoveDeathRecipient(deathRecipientMap_[object.GetRefPtr()]);
245         deathRecipientMap_.erase(object.GetRefPtr());
246     }
247 
248     callbackToHandleMap_.erase(object.GetRefPtr());
249     INTELLIGENT_VOICE_LOGI("handle set is empty, remove death recipient");
250 }
251 
Clean(IRemoteObject * remote)252 void IntellVoiceTriggerAdapterImpl::Clean(IRemoteObject *remote)
253 {
254     std::lock_guard<std::mutex> lock(mutex_);
255     INTELLIGENT_VOICE_LOGI("enter");
256     if (remote == nullptr) {
257         INTELLIGENT_VOICE_LOGE("remote is nullptr");
258         return;
259     }
260 
261     if (callbackToHandleMap_.count(remote) == 0) {
262         INTELLIGENT_VOICE_LOGE("no remote");
263         return;
264     }
265 
266     MemoryGuard memoryGuard;
267     for (auto it = callbackToHandleMap_[remote].begin(); it != callbackToHandleMap_[remote].end(); ++it) {
268         INTELLIGENT_VOICE_LOGI("unload model, id is %{public}d", *it);
269         (void)adapter_->UnloadIntellVoiceTriggerModel(*it);
270         handleToCallbackMap_.erase(*it);
271     }
272 
273     callbackToHandleMap_.erase(remote);
274     deathRecipientMap_.erase(remote);
275 }
276 }  // namespace Trigger
277 }  // namespace IntelligentVoice
278 }  // namespace OHOS