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 <thread>
16
17 #include "trigger_connector_internal_impl.h"
18 #include "intell_voice_log.h"
19 #include "v1_1/iintell_voice_trigger_manager.h"
20 #include "scope_guard.h"
21 #include "trigger_callback_impl.h"
22 #include "memory_guard.h"
23 #include "iproxy_broker.h"
24 #include "intell_voice_death_recipient.h"
25
26 #define LOG_TAG "TriggerConnector"
27
28 using namespace std;
29 using namespace OHOS::HDI::ServiceManager::V1_0;
30 using namespace OHOS::IntellVoiceUtils;
31 using namespace OHOS::HDI::IntelligentVoice::Trigger::V1_0;
32 using namespace OHOS::HDI::IntelligentVoice::Trigger::V1_1;
33
34 namespace OHOS {
35 namespace IntellVoiceTrigger {
36 static constexpr uint32_t MAX_RECOGNITION_EVENT_NUM = 100;
37 static const std::string INTELL_VOICE_TRIGGER_SERVICE = "intell_voice_trigger_manager_service";
38 static const std::string THREAD_NAME = "TriggerThread_";
39
TriggerConnector(OnServiceStartCb cb,const IntellVoiceTriggerAdapterDsecriptor & desc)40 TriggerConnector::TriggerConnector(OnServiceStartCb cb, const IntellVoiceTriggerAdapterDsecriptor &desc) : cb_(cb)
41 {
42 desc_.adapterName = desc.adapterName;
43 LoadHdiAdapter();
44 }
45
~TriggerConnector()46 TriggerConnector::~TriggerConnector()
47 {
48 TriggerHostManager::UnloadTriggerAdapter(desc_);
49 }
50
LoadHdiAdapter()51 bool TriggerConnector::LoadHdiAdapter()
52 {
53 if (!TriggerHostManager::Init()) {
54 INTELL_VOICE_LOG_WARN("failed to init trigger host manager");
55 return false;
56 }
57
58 TriggerHostManager::RegisterTriggerHDIDeathRecipient();
59 if (!TriggerHostManager::LoadTriggerAdapter(desc_)) {
60 INTELL_VOICE_LOG_ERROR("failed to load trigger adapter");
61 return false;
62 }
63
64 return true;
65 }
66
GetModule(std::shared_ptr<IIntellVoiceTriggerConnectorCallback> callback)67 std::shared_ptr<IIntellVoiceTriggerConnectorModule> TriggerConnector::GetModule(
68 std::shared_ptr<IIntellVoiceTriggerConnectorCallback> callback)
69 {
70 INTELL_VOICE_LOG_INFO("enter");
71 if (callback == nullptr) {
72 INTELL_VOICE_LOG_ERROR("callback is nullptr");
73 return nullptr;
74 }
75
76 std::lock_guard<std::mutex> lock(mutex_);
77 do {
78 if (TriggerHostManager::GetAdapter() != nullptr) {
79 INTELL_VOICE_LOG_INFO("already load hdi adapter");
80 break;
81 }
82 INTELL_VOICE_LOG_INFO("start to load hdi adapter");
83 if (!LoadHdiAdapter()) {
84 getModuleFail_ = true;
85 return nullptr;
86 }
87 } while (0);
88
89 getModuleFail_ = false;
90 std::shared_ptr<TriggerSession> session = std::make_shared<TriggerSession>(this, callback, activeSessions_.size());
91 if (session == nullptr) {
92 INTELL_VOICE_LOG_ERROR("failed to malloc session");
93 return nullptr;
94 }
95
96 activeSessions_.insert(session);
97 return session;
98 }
99
GetProperties()100 IntellVoiceTriggerProperties TriggerConnector::GetProperties()
101 {
102 IntellVoiceTriggerProperties properties;
103 return properties;
104 }
105
OnReceive(const ServiceStatus & serviceStatus)106 void TriggerConnector::OnReceive(const ServiceStatus &serviceStatus)
107 {
108 if (serviceStatus.serviceName != INTELL_VOICE_TRIGGER_SERVICE) {
109 return;
110 }
111
112 INTELL_VOICE_LOG_INFO("status:%{public}d", serviceStatus.status);
113 std::lock_guard<std::mutex> lock(mutex_);
114 if (serviceStatus.status == serviceState_) {
115 INTELL_VOICE_LOG_INFO("service state not change");
116 return;
117 }
118
119 serviceState_ = serviceStatus.status;
120 if ((!getModuleFail_) || (serviceState_ != SERVIE_STATUS_START) || (TriggerHostManager::GetAdapter() != nullptr)) {
121 INTELL_VOICE_LOG_INFO("no need to notify mgr, getModuleFail:%{public}d, service state:%{public}d",
122 getModuleFail_, serviceState_);
123 return;
124 }
125
126 if (cb_ != nullptr) {
127 cb_(desc_);
128 }
129 }
130
TriggerSession(TriggerConnector * connector,std::shared_ptr<IIntellVoiceTriggerConnectorCallback> callback,uint32_t threadId)131 TriggerConnector::TriggerSession::TriggerSession(TriggerConnector *connector,
132 std::shared_ptr<IIntellVoiceTriggerConnectorCallback> callback, uint32_t threadId)
133 : TaskExecutor(THREAD_NAME + std::to_string(threadId), MAX_RECOGNITION_EVENT_NUM),
134 connector_(connector), callback_(callback)
135 {
136 TaskExecutor::StartThread();
137 }
138
~TriggerSession()139 TriggerConnector::TriggerSession::~TriggerSession()
140 {
141 loadedModels_.clear();
142 TaskExecutor::StopThread();
143 }
144
LoadModel(std::shared_ptr<GenericTriggerModel> model,int32_t & modelHandle)145 int32_t TriggerConnector::TriggerSession::LoadModel(std::shared_ptr<GenericTriggerModel> model, int32_t &modelHandle)
146 {
147 std::lock_guard<std::mutex> lock(connector_->mutex_);
148 if (connector_->TriggerHostManager::GetAdapter() == nullptr) {
149 INTELL_VOICE_LOG_ERROR("adapter is nullptr");
150 return -1;
151 }
152 std::shared_ptr<Model> loadedModle = Model::Create(this);
153 if (loadedModle == nullptr) {
154 INTELL_VOICE_LOG_ERROR("failed to malloc intell voice model");
155 return -1;
156 }
157
158 int32_t result = loadedModle->Load(model, modelHandle);
159 if (result != 0) {
160 INTELL_VOICE_LOG_ERROR("failed to load generic trigger model");
161 return result;
162 }
163 loadedModels_.insert(std::make_pair(modelHandle, loadedModle));
164 return result;
165 }
166
UnloadModel(int32_t modelHandle)167 int32_t TriggerConnector::TriggerSession::UnloadModel(int32_t modelHandle)
168 {
169 std::lock_guard<std::mutex> lock(connector_->mutex_);
170 if (connector_->TriggerHostManager::GetAdapter() == nullptr) {
171 INTELL_VOICE_LOG_ERROR("adapter is nullptr");
172 return -1;
173 }
174 auto it = loadedModels_.find(modelHandle);
175 if ((it == loadedModels_.end()) || (it->second == nullptr)) {
176 INTELL_VOICE_LOG_ERROR("failed to find model");
177 return -1;
178 }
179
180 int32_t ret = it->second->Unload();
181 loadedModels_.erase(it);
182 return ret;
183 }
184
Start(int32_t modelHandle)185 int32_t TriggerConnector::TriggerSession::Start(int32_t modelHandle)
186 {
187 std::lock_guard<std::mutex> lock(connector_->mutex_);
188 if (connector_->TriggerHostManager::GetAdapter() == nullptr) {
189 INTELL_VOICE_LOG_ERROR("adapter is nullptr");
190 return -1;
191 }
192 auto it = loadedModels_.find(modelHandle);
193 if ((it == loadedModels_.end()) || (it->second == nullptr)) {
194 INTELL_VOICE_LOG_ERROR("failed to find model");
195 return -1;
196 }
197 return it->second->Start();
198 }
199
Stop(int32_t modelHandle)200 int32_t TriggerConnector::TriggerSession::Stop(int32_t modelHandle)
201 {
202 std::lock_guard<std::mutex> lock(connector_->mutex_);
203 if (connector_->TriggerHostManager::GetAdapter() == nullptr) {
204 INTELL_VOICE_LOG_ERROR("adapter is nullptr");
205 return -1;
206 }
207 auto it = loadedModels_.find(modelHandle);
208 if ((it == loadedModels_.end()) || (it->second == nullptr)) {
209 INTELL_VOICE_LOG_ERROR("failed to find model");
210 return -1;
211 }
212 return it->second->Stop();
213 }
214
SetParams(const std::string & key,const std::string & value)215 int32_t TriggerConnector::TriggerSession::SetParams(const std::string& key, const std::string& value)
216 {
217 std::lock_guard<std::mutex> lock(connector_->mutex_);
218 if (connector_->TriggerHostManager::GetAdapterV1_1() == nullptr) {
219 INTELL_VOICE_LOG_ERROR("adapter is nullptr");
220 return -1;
221 }
222
223 int32_t ret = connector_->TriggerHostManager::GetAdapterV1_1()->SetParams(key, value);
224 if (ret != 0) {
225 INTELL_VOICE_LOG_ERROR("failed to set params");
226 }
227
228 return ret;
229 }
230
GetParams(const std::string & key,std::string & value)231 int32_t TriggerConnector::TriggerSession::GetParams(const std::string& key, std::string &value)
232 {
233 std::lock_guard<std::mutex> lock(connector_->mutex_);
234 if (connector_->TriggerHostManager::GetAdapterV1_1() == nullptr) {
235 INTELL_VOICE_LOG_ERROR("adapter is nullptr");
236 return -1;
237 }
238
239 return connector_->TriggerHostManager::GetAdapterV1_1()->GetParams(key, value);
240 }
241
HandleRecognitionHdiEvent(std::shared_ptr<IntellVoiceRecognitionEvent> event,int32_t modelHandle)242 void TriggerConnector::TriggerSession::HandleRecognitionHdiEvent(
243 std::shared_ptr<IntellVoiceRecognitionEvent> event, int32_t modelHandle)
244 {
245 std::function<void()> func = std::bind(
246 &TriggerConnector::TriggerSession::ProcessRecognitionHdiEvent, this, event, modelHandle);
247 TaskExecutor::AddAsyncTask(func);
248 }
249
ProcessRecognitionHdiEvent(std::shared_ptr<IntellVoiceRecognitionEvent> event,int32_t modelHandle)250 void TriggerConnector::TriggerSession::ProcessRecognitionHdiEvent(
251 std::shared_ptr<IntellVoiceRecognitionEvent> event, int32_t modelHandle)
252 {
253 if (event == nullptr) {
254 INTELL_VOICE_LOG_ERROR("event is nullptr");
255 return;
256 }
257 if (connector_ == nullptr) {
258 INTELL_VOICE_LOG_ERROR("connector is nullptr");
259 return;
260 }
261
262 {
263 std::lock_guard<std::mutex> lock(connector_->mutex_);
264 auto it = loadedModels_.find(modelHandle);
265 if ((it == loadedModels_.end()) || (it->second == nullptr)) {
266 INTELL_VOICE_LOG_ERROR("can not find model, handle:%{public}d", modelHandle);
267 return;
268 }
269
270 if (it->second->GetState() != Model::ModelState::ACTIVE) {
271 INTELL_VOICE_LOG_ERROR("unexpected recognition event, handle:%{public}d", modelHandle);
272 return;
273 }
274
275 it->second->SetState(Model::ModelState::LOADED);
276 }
277 callback_->OnRecognition(modelHandle, *(event.get()));
278 }
279
Create(TriggerSession * session)280 std::shared_ptr<TriggerConnector::TriggerSession::Model> TriggerConnector::TriggerSession::Model::Create(
281 TriggerSession *session)
282 {
283 return std::shared_ptr<Model>(new (std::nothrow) Model(session));
284 }
285
Load(std::shared_ptr<GenericTriggerModel> model,int32_t & modelHandle)286 int32_t TriggerConnector::TriggerSession::Model::Load(std::shared_ptr<GenericTriggerModel> model, int32_t &modelHandle)
287 {
288 INTELL_VOICE_LOG_INFO("enter");
289 if (GetState() != IDLE) {
290 INTELL_VOICE_LOG_ERROR("model has already loaded");
291 return -1;
292 }
293
294 callback_ = sptr<IIntellVoiceTriggerCallback>(new (std::nothrow) TriggerCallbackImpl(shared_from_this()));
295 if (callback_ == nullptr) {
296 INTELL_VOICE_LOG_ERROR("callback_ is nullptr");
297 return -1;
298 }
299
300 IntellVoiceTriggerModel triggerModel;
301 triggerModel.data = CreateAshmemFromModelData(model->GetData());
302 if (triggerModel.data == nullptr) {
303 INTELL_VOICE_LOG_ERROR("data is nullptr");
304 return -1;
305 }
306 triggerModel.type = static_cast<IntellVoiceTriggerModelType>(model->GetType());
307 triggerModel.uid = static_cast<uint32_t>(model->GetUuid());
308
309 ON_SCOPE_EXIT
310 {
311 INTELL_VOICE_LOG_INFO("close ashmem");
312 triggerModel.data->UnmapAshmem();
313 triggerModel.data->CloseAshmem();
314 };
315
316 int32_t handle;
317 int32_t ret = session_->GetTriggerConnector()->TriggerHostManager::GetAdapter()->LoadModel(triggerModel,
318 callback_, 0, handle);
319 if (ret != 0) {
320 INTELL_VOICE_LOG_ERROR("failed to load model");
321 return ret;
322 }
323 (void)model;
324 handle_ = handle;
325 modelHandle = handle_;
326 SetState(LOADED);
327 return ret;
328 }
329
Start()330 int32_t TriggerConnector::TriggerSession::Model::Start()
331 {
332 INTELL_VOICE_LOG_INFO("enter");
333 if (GetState() != LOADED) {
334 INTELL_VOICE_LOG_ERROR("model has not loaded");
335 return -1;
336 }
337
338 int32_t ret = session_->GetTriggerConnector()->TriggerHostManager::GetAdapter()->Start(handle_);
339 if (ret != 0) {
340 INTELL_VOICE_LOG_ERROR("failed to load model");
341 return ret;
342 }
343
344 #ifdef TRIGGER_MANAGER_TEST
345 std::thread(&TriggerConnector::TriggerSession::Model::TriggerManagerCallbackTest, this).detach();
346 #endif
347
348 SetState(ACTIVE);
349 return ret;
350 }
351
Stop()352 int32_t TriggerConnector::TriggerSession::Model::Stop()
353 {
354 INTELL_VOICE_LOG_INFO("enter");
355 if (GetState() != ACTIVE) {
356 INTELL_VOICE_LOG_ERROR("model has not activated");
357 return -1;
358 }
359
360 int32_t ret = session_->GetTriggerConnector()->TriggerHostManager::GetAdapter()->Stop(handle_);
361 if (ret != 0) {
362 INTELL_VOICE_LOG_ERROR("failed to load model");
363 return ret;
364 }
365
366 SetState(LOADED);
367 return ret;
368 }
369
Unload()370 int32_t TriggerConnector::TriggerSession::Model::Unload()
371 {
372 INTELL_VOICE_LOG_INFO("enter");
373 if (GetState() == IDLE) {
374 INTELL_VOICE_LOG_ERROR("model has not loaded");
375 return -1;
376 }
377
378 int32_t ret = session_->GetTriggerConnector()->TriggerHostManager::GetAdapter()->UnloadModel(handle_);
379 if (ret != 0) {
380 INTELL_VOICE_LOG_ERROR("failed to load model");
381 return ret;
382 }
383
384 SetState(IDLE);
385 return ret;
386 }
387
388 #ifdef TRIGGER_MANAGER_TEST
TriggerManagerCallbackTest()389 void TriggerConnector::TriggerSession::Model::TriggerManagerCallbackTest()
390 {
391 INTELL_VOICE_LOG_ERROR("enter");
392 IntellVoiceRecognitionEvent recognitionEvent;
393 recognitionEvent.status = static_cast<RecognitionStatus>(0);
394 recognitionEvent.type = static_cast<IntellVoiceTriggerModelType>(1);
395 recognitionEvent.modelHandle = handle_;
396 TriggerConnector::TriggerSession::Model::OnRecognitionHdiEvent(recognitionEvent, 0);
397 }
398 #endif
399
OnRecognitionHdiEvent(const IntellVoiceRecognitionEvent & event,int32_t cookie)400 void TriggerConnector::TriggerSession::Model::OnRecognitionHdiEvent(
401 const IntellVoiceRecognitionEvent &event, int32_t cookie)
402 {
403 (void)cookie;
404 std::shared_ptr<IntellVoiceRecognitionEvent> recognitionEvent = std::make_shared<IntellVoiceRecognitionEvent>();
405 if (recognitionEvent == nullptr) {
406 INTELL_VOICE_LOG_ERROR("recognitionEvent is nullptr");
407 return;
408 }
409
410 recognitionEvent->status = event.status;
411 recognitionEvent->type = event.type;
412 recognitionEvent->modelHandle = event.modelHandle;
413
414 INTELL_VOICE_LOG_INFO("handle: %{public}d", handle_);
415 session_->HandleRecognitionHdiEvent(recognitionEvent, handle_);
416 }
417
CreateAshmemFromModelData(const std::vector<uint8_t> & modelData)418 sptr<Ashmem> TriggerConnector::TriggerSession::Model::CreateAshmemFromModelData(const std::vector<uint8_t> &modelData)
419 {
420 if (modelData.size() == 0) {
421 INTELL_VOICE_LOG_ERROR("data is empty");
422 return nullptr;
423 }
424
425 sptr<Ashmem> buffer = OHOS::Ashmem::CreateAshmem("ModelData", modelData.size());
426 if (buffer == nullptr) {
427 INTELL_VOICE_LOG_ERROR("failed to create ashmem");
428 return nullptr;
429 }
430
431 if (!buffer->MapReadAndWriteAshmem()) {
432 INTELL_VOICE_LOG_ERROR("failed to map ashmem");
433 goto ERR_EXIT;
434 }
435
436 if (!buffer->WriteToAshmem(modelData.data(), modelData.size(), 0)) {
437 INTELL_VOICE_LOG_ERROR("failed to write ashmem");
438 goto ERR_EXIT;
439 }
440
441 INTELL_VOICE_LOG_INFO("model data size:%{public}zu", modelData.size());
442 return buffer;
443
444 ERR_EXIT:
445 buffer->UnmapAshmem();
446 buffer->CloseAshmem();
447 return nullptr;
448 }
449 } // namespace IntellVoiceTrigger
450 } // namespace OHOS