• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022 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 
16 #include <uv.h>
17 
18 #include "client_helper.h"
19 #include "node_api.h"
20 #include "update_helper.h"
21 #include "update_session.h"
22 #include "session_manager.h"
23 
24 using namespace std;
25 
26 namespace OHOS {
27 namespace UpdateEngine {
28 struct NotifyInput {
29     NotifyInput() = default;
NotifyInputOHOS::UpdateEngine::NotifyInput30     NotifyInput(SessionManager *sesssionManager, const string &itype, UpdateResult *iresult)
31         : sesssionMgr(sesssionManager), type(itype), result(iresult) {}
32     SessionManager *sesssionMgr = nullptr;
33     string type;
34     UpdateResult *result = nullptr;
35 };
36 
SessionManager(napi_env env,napi_ref thisReference)37 SessionManager::SessionManager(napi_env env, napi_ref thisReference) : env_(env), thisReference_(thisReference) {}
38 
~SessionManager()39 SessionManager::~SessionManager()
40 {
41     sessions_.clear();
42     if (thisReference_ != nullptr) {
43         napi_delete_reference(env_, thisReference_);
44     }
45 }
46 
AddSession(std::shared_ptr<IUpdateSession> session)47 void SessionManager::AddSession(std::shared_ptr<IUpdateSession> session)
48 {
49     PARAM_CHECK(session != nullptr, return, "Invalid param");
50 #ifndef UPDATER_API_TEST
51     std::lock_guard<std::mutex> guard(sessionMutex_);
52 #endif
53     sessions_.insert(make_pair(session->GetSessionId(), session));
54 }
55 
RemoveSession(uint32_t sessionId)56 void SessionManager::RemoveSession(uint32_t sessionId)
57 {
58     CLIENT_LOGI("RemoveSession sess");
59 #ifndef UPDATER_API_TEST
60     std::lock_guard<std::mutex> guard(sessionMutex_);
61 #endif
62     IUpdateSession *sess = nullptr;
63     auto iter = sessions_.find(sessionId);
64     if (iter != sessions_.end()) {
65         sess = iter->second.get();
66         sessions_.erase(iter);
67     }
68 }
69 
Clear()70 void SessionManager::Clear()
71 {
72     sessions_.clear();
73     if (thisReference_ != nullptr) {
74         napi_delete_reference(env_, thisReference_);
75     }
76 }
77 
GetFirstSessionId(uint32_t & sessionId)78 bool SessionManager::GetFirstSessionId(uint32_t &sessionId)
79 {
80 #ifndef UPDATER_API_TEST
81     std::lock_guard<std::mutex> guard(sessionMutex_);
82 #endif
83     {
84         if (sessions_.empty()) {
85             return false;
86         }
87         sessionId = sessions_.begin()->second->GetSessionId();
88         return true;
89     }
90 }
91 
GetNextSessionId(uint32_t & sessionId)92 bool SessionManager::GetNextSessionId(uint32_t &sessionId)
93 {
94 #ifndef UPDATER_API_TEST
95     std::lock_guard<std::mutex> guard(sessionMutex_);
96 #endif
97     {
98         auto iter = sessions_.find(sessionId);
99         if (iter == sessions_.end()) {
100             return false;
101         }
102         iter++;
103         if (iter == sessions_.end()) {
104             return false;
105         }
106         sessionId = iter->second->GetSessionId();
107     }
108     return true;
109 }
110 
ProcessUnsubscribe(const std::string & eventType,size_t argc,napi_value arg)111 int32_t SessionManager::ProcessUnsubscribe(const std::string &eventType, size_t argc, napi_value arg)
112 {
113     napi_handle_scope scope;
114     napi_status status = napi_open_handle_scope(env_, &scope);
115     PARAM_CHECK(status == napi_ok, return -1, "Error open handle");
116 
117     uint32_t nextSessId = 0;
118     bool hasNext = GetFirstSessionId(nextSessId);
119     while (hasNext) {
120         uint32_t currSessId = nextSessId;
121         auto iter = sessions_.find(currSessId);
122         if (iter == sessions_.end()) {
123             break;
124         }
125         hasNext = GetNextSessionId(nextSessId);
126 
127         UpdateListener *listener = static_cast<UpdateListener *>(iter->second.get());
128         if (listener->GetType() != SessionType::SESSION_SUBSCRIBE ||
129             eventType.compare(listener->GetEventType()) != 0) {
130             continue;
131         }
132         CLIENT_LOGI("ProcessUnsubscribe remove session");
133         if (argc == 1) {
134             listener->RemoveHandlerRef(env_);
135             RemoveSession(currSessId);
136         } else if (listener->CheckEqual(env_, arg, eventType)) {
137             listener->RemoveHandlerRef(env_);
138             RemoveSession(currSessId);
139             break;
140         }
141     }
142     napi_close_handle_scope(env_, scope);
143     return 0;
144 }
145 
Unsubscribe(const EventClassifyInfo & eventClassifyInfo,napi_value handle)146 void SessionManager::Unsubscribe(const EventClassifyInfo &eventClassifyInfo, napi_value handle)
147 {
148     std::lock_guard<std::mutex> guard(sessionMutex_);
149     for (auto iter = sessions_.begin(); iter != sessions_.end();) {
150         if (iter->second == nullptr) {
151             iter = sessions_.erase(iter); // erase nullptr
152             continue;
153         }
154 
155         if (iter->second->GetType() != SessionType::SESSION_SUBSCRIBE) {
156             ++iter;
157             continue;
158         }
159 
160         auto listener = static_cast<UpdateListener *>(iter->second.get());
161         if (handle == nullptr && listener->IsSubscribeEvent(eventClassifyInfo)) {
162             CLIENT_LOGI("Unsubscribe, remove session %{public}d without handle", listener->GetSessionId());
163             iter = sessions_.erase(iter);
164             continue;
165         }
166 
167         if (listener->IsSameListener(env_, eventClassifyInfo, handle)) {
168             CLIENT_LOGI("Unsubscribe, remove session %{public}d", listener->GetSessionId());
169             iter = sessions_.erase(iter);
170             continue;
171         }
172 
173         ++iter;
174     }
175 }
176 
FindSessionByHandle(napi_env env,const std::string & eventType,napi_value arg)177 IUpdateSession *SessionManager::FindSessionByHandle(napi_env env, const std::string &eventType, napi_value arg)
178 {
179     uint32_t nextSessId = 0;
180     bool hasNext = GetFirstSessionId(nextSessId);
181     while (hasNext) {
182         uint32_t currSessId = nextSessId;
183         auto iter = sessions_.find(currSessId);
184         if (iter == sessions_.end()) {
185             break;
186         }
187         hasNext = GetNextSessionId(nextSessId);
188 
189         UpdateListener *listener = static_cast<UpdateListener *>(iter->second.get());
190         if (listener->GetType() != SessionType::SESSION_SUBSCRIBE) {
191             continue;
192         }
193         if ((eventType.compare(listener->GetEventType()) == 0) && listener->CheckEqual(env_, arg, eventType)) {
194             return listener;
195         }
196     }
197     return nullptr;
198 }
199 
FindSessionByHandle(napi_env env,const EventClassifyInfo & eventClassifyInfo,napi_value arg)200 IUpdateSession *SessionManager::FindSessionByHandle(napi_env env, const EventClassifyInfo &eventClassifyInfo,
201     napi_value arg)
202 {
203     std::lock_guard<std::mutex> guard(sessionMutex_);
204     for (auto &iter : sessions_) {
205         if (iter.second == nullptr) {
206             continue;
207         }
208 
209         if (iter.second->GetType() != SessionType::SESSION_SUBSCRIBE) {
210             continue;
211         }
212 
213         auto listener = static_cast<UpdateListener *>(iter.second.get());
214         if (listener->IsSameListener(env, eventClassifyInfo, arg)) {
215             return listener;
216         }
217     }
218     return nullptr;
219 }
220 
PublishToJS(const std::string & type,const UpdateResult & result)221 void SessionManager::PublishToJS(const std::string &type, const UpdateResult &result)
222 {
223     CLIENT_LOGI("PublishToJS %{public}s", type.c_str());
224     napi_handle_scope scope;
225     napi_status status = napi_open_handle_scope(env_, &scope);
226     PARAM_CHECK_NAPI_CALL(env_, status == napi_ok, return, "Error open_handle_scope");
227     napi_value thisVar = nullptr;
228     status = napi_get_reference_value(env_, thisReference_, &thisVar);
229     PARAM_CHECK_NAPI_CALL(env_, status == napi_ok, napi_close_handle_scope(env_, scope); return,
230         "Error get_reference");
231 
232     uint32_t nextSessId = 0;
233     bool hasNext = GetFirstSessionId(nextSessId);
234     while (hasNext) {
235         uint32_t currSessId = nextSessId;
236         auto iter = sessions_.find(currSessId);
237         if (iter == sessions_.end()) {
238             break;
239         }
240         hasNext = GetNextSessionId(nextSessId);
241         if (iter->second == nullptr) {
242             CLIENT_LOGE("PublishToJS error, updateSession is null, %{public}d", iter->first);
243             continue;
244         }
245         IUpdateSession *updateSession = (iter->second).get();
246         CLIENT_LOGI("PublishToJS GetType %{public}d", updateSession->GetType());
247         if (updateSession->GetType() == SessionType::SESSION_SUBSCRIBE) {
248             UpdateListener *listener = static_cast<UpdateListener *>(updateSession);
249             if (type.compare(listener->GetEventType()) != 0) {
250                 continue;
251             }
252 
253             listener->NotifyJS(env_, thisVar, result);
254             if (listener->IsOnce()) {
255                 listener->RemoveHandlerRef(env_);
256                 RemoveSession(currSessId);
257             }
258         } else if (updateSession->IsAsyncCompleteWork()) {
259             updateSession->NotifyJS(env_, thisVar, result);
260             RemoveSession(currSessId);
261         } else {
262             CLIENT_LOGI("PublishToJS GetType unknown type");
263         }
264     }
265     napi_close_handle_scope(env_, scope);
266 }
267 
PublishToJS(const EventClassifyInfo & eventClassifyInfo,const EventInfo & eventInfo)268 void SessionManager::PublishToJS(const EventClassifyInfo &eventClassifyInfo, const EventInfo &eventInfo)
269 {
270     napi_handle_scope scope;
271     napi_status status = napi_open_handle_scope(env_, &scope);
272     PARAM_CHECK_NAPI_CALL(env_, status == napi_ok, return, "Error open_handle_scope");
273     napi_value thisVar = nullptr;
274     status = napi_get_reference_value(env_, thisReference_, &thisVar);
275     PARAM_CHECK_NAPI_CALL(env_, status == napi_ok, napi_close_handle_scope(env_, scope); return,
276         "Error get_reference");
277 
278     std::lock_guard<std::mutex> guard(sessionMutex_);
279     for (auto &iter : sessions_) {
280         if (iter.second == nullptr) {
281             continue;
282         }
283 
284         if (iter.second->GetType() != SessionType::SESSION_SUBSCRIBE) {
285             continue;
286         }
287 
288         UpdateListener *listener = static_cast<UpdateListener *>(iter.second.get());
289         if (!listener->IsSubscribeEvent(eventClassifyInfo)) {
290             continue;
291         }
292 
293         listener->NotifyJS(env_, thisVar, eventInfo);
294     }
295     napi_close_handle_scope(env_, scope);
296 }
297 
Emit(const std::string & type,const UpdateResult & result)298 void SessionManager::Emit(const std::string &type, const UpdateResult &result)
299 {
300     auto freeUpdateResult = [](UpdateResult *lres) {
301         if (lres != nullptr) {
302             lres->Release();
303         }
304         delete lres;
305     };
306     CLIENT_LOGI("SessionManager::Emit %{public}s", type.c_str());
307 
308     UpdateResult *res = new (std::nothrow) UpdateResult();
309     if (res == nullptr) {
310         return;
311     }
312     *res = result;
313     uv_loop_s *loop = nullptr;
314     napi_get_uv_event_loop(env_, &loop);
315     PARAM_CHECK(loop != nullptr, freeUpdateResult(res); return, "get event loop failed.");
316 
317     uv_work_t *work = new (std::nothrow) uv_work_t;
318     PARAM_CHECK(work != nullptr, freeUpdateResult(res); return, "alloc work failed.");
319 
320     work->data = (void *)new (std::nothrow) NotifyInput(this, type, res);
321     PARAM_CHECK(work->data != nullptr, freeUpdateResult(res); delete work; return, "alloc work data failed.");
322 
323     uv_queue_work(
324         loop,
325         work,
326         [](uv_work_t *work) {}, // run in C++ thread
327         [](uv_work_t *work, int status) {
328             NotifyInput *input = (NotifyInput *)work->data;
329             input->sesssionMgr->PublishToJS(input->type, *input->result);
330             input->result->Release();
331             delete input->result;
332             delete input;
333             delete work;
334         });
335 }
336 
Emit(const EventClassifyInfo & eventClassifyInfo,const EventInfo & eventInfo)337 void SessionManager::Emit(const EventClassifyInfo &eventClassifyInfo, const EventInfo &eventInfo)
338 {
339     CLIENT_LOGI("SessionManager::Emit 0x%{public}x", CAST_INT(eventClassifyInfo.eventClassify));
340     uv_loop_s *loop = nullptr;
341     napi_get_uv_event_loop(env_, &loop);
342     PARAM_CHECK(loop != nullptr, return, "get event loop failed.");
343 
344     using UvWorkData = std::tuple<SessionManager*, EventClassifyInfo, EventInfo>;
345     UvWorkData* data = new (std::nothrow) std::tuple(this, eventClassifyInfo, eventInfo);
346     PARAM_CHECK(data != nullptr, return, "alloc data failed.");
347 
348     uv_work_t *work = new (std::nothrow) uv_work_t;
349     PARAM_CHECK(work != nullptr, delete data; return, "alloc work failed.");
350 
351     work->data = static_cast<void *>(data);
352     uv_queue_work(
353         loop,
354         work,
355         [](uv_work_t *work) {},
356         [](uv_work_t *work, int status) {
357             UvWorkData *data = static_cast<UvWorkData*>(work->data);
358             auto &[mgr, eventClassifyInfo, eventInfo] = *data;
359             mgr->PublishToJS(eventClassifyInfo, eventInfo);
360             delete data;
361             delete work;
362         });
363 }
364 } // namespace UpdateEngine
365 } // namespace OHOS