1 /*
2 * Copyright (c) 2024 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 "js_native_api.h"
17 #include "js_native_api_types.h"
18 #include "napi/native_common.h"
19
20 #include "client_helper.h"
21 #include "define_property.h"
22 #include "local_updater.h"
23 #include "restorer.h"
24 #include "update_client.h"
25 #include "update_define.h"
26
27 namespace OHOS::UpdateEngine {
28 // class name
29 const std::string CLASS_NAME_UPDATE_CLIENT = "UpdateClient";
30 const std::string CLASS_NAME_RESTORER = "Restorer";
31 const std::string CLASS_NAME_LOCAL_UPDATER = "LocalUpdater";
32
33 // constructor reference
34 static thread_local napi_ref g_updateClientConstructorRef = nullptr;
35 static thread_local napi_ref g_restorerConstructorRef = nullptr;
36 static thread_local napi_ref g_localUpdaterConstructorRef = nullptr;
37
38 std::shared_ptr<Restorer> g_restorer = nullptr;
39 std::shared_ptr<LocalUpdater> g_localUpdater = nullptr;
40 std::map<UpgradeInfo, std::shared_ptr<UpdateClient>> g_onlineUpdater;
41
42 template<typename T, typename Initializer, typename Finalizer>
JsConstructor(napi_env env,napi_callback_info info,Initializer initializer,Finalizer finalizer)43 napi_value JsConstructor(napi_env env, napi_callback_info info, Initializer initializer, Finalizer finalizer)
44 {
45 size_t argc = MAX_ARGC;
46 napi_value args[MAX_ARGC] = { 0 };
47 napi_value thisVar = nullptr;
48 void* data = nullptr;
49 napi_get_cb_info(env, info, &argc, args, &thisVar, &data);
50
51 T* object = initializer(env, thisVar, args[0]);
52 if (object == nullptr) {
53 return thisVar;
54 }
55 napi_wrap(env, thisVar, object, finalizer, nullptr, nullptr);
56 return thisVar;
57 }
58
59 template<typename T>
JsConstructor(napi_env env,napi_callback_info info)60 napi_value JsConstructor(napi_env env, napi_callback_info info)
61 {
62 auto initializer = [](napi_env env, napi_value value, const napi_value arg) {
63 UpgradeInfo upgradeInfo;
64 ClientStatus ret = ClientHelper::GetUpgradeInfoFromArg(env, arg, upgradeInfo);
65 if (ret != ClientStatus::CLIENT_SUCCESS) {
66 ENGINE_LOGE("JsConstructor GetUpgradeInfoFromArg error");
67 T* object = NULL;
68 return object;
69 }
70 if (g_onlineUpdater.count(upgradeInfo) == 0) {
71 ENGINE_LOGI("JsConstructor new UpdateClient subtype: %{public}d", upgradeInfo.businessType.subType);
72 std::shared_ptr<UpdateClient> updateClient = std::make_shared<UpdateClient>(env, value);
73 g_onlineUpdater[upgradeInfo] = updateClient;
74 } else {
75 ENGINE_LOGI("JsConstructor UpdateClient use cache");
76 }
77 return g_onlineUpdater[upgradeInfo].get();
78 };
79
80 auto finalizer = [](napi_env env, void* data, void* hint) {
81 ENGINE_LOGI("delete js object");
82 };
83
84 return JsConstructor<T>(env, info, initializer, finalizer);
85 }
86
JsConstructorRestorer(napi_env env,napi_callback_info info)87 napi_value JsConstructorRestorer(napi_env env, napi_callback_info info)
88 {
89 auto initializer = [](napi_env env, napi_value value, const napi_value arg) {
90 if (g_restorer == nullptr) {
91 ENGINE_LOGI("JsConstructorRestorer, create native object");
92 g_restorer = std::make_shared<Restorer>(env, value);
93 }
94 return g_restorer.get();
95 };
96 auto finalizer = [](napi_env env, void* data, void* hint) {};
97 return JsConstructor<Restorer>(env, info, initializer, finalizer);
98 }
99
JsConstructorLocalUpdater(napi_env env,napi_callback_info info)100 napi_value JsConstructorLocalUpdater(napi_env env, napi_callback_info info)
101 {
102 auto initializer = [](napi_env env, napi_value value, const napi_value arg) {
103 if (g_localUpdater == nullptr) {
104 ENGINE_LOGI("JsConstructorLocalUpdater, create native object");
105 g_localUpdater = std::make_shared<LocalUpdater>(env, value);
106 }
107 return g_localUpdater.get();
108 };
109 auto finalizer = [](napi_env env, void* data, void* hint) {};
110 return JsConstructor<LocalUpdater>(env, info, initializer, finalizer);
111 }
112
GetOnlineUpdater(napi_env env,napi_callback_info info)113 napi_value GetOnlineUpdater(napi_env env, napi_callback_info info)
114 {
115 napi_value jsObject = nullptr;
116 UpdateClient *client = CreateJsObject<UpdateClient>(env, info, g_updateClientConstructorRef, jsObject);
117 if (client != nullptr) {
118 napi_value result = client->GetOnlineUpdater(env, info);
119 if (result != nullptr) {
120 return jsObject;
121 }
122 }
123 return nullptr;
124 }
125
GetRestorer(napi_env env,napi_callback_info info)126 napi_value GetRestorer(napi_env env, napi_callback_info info)
127 {
128 napi_value jsObject = nullptr;
129 Restorer* restorer = CreateJsObject<Restorer>(env, info, g_restorerConstructorRef, jsObject);
130 if (restorer == nullptr) {
131 return nullptr;
132 }
133 return jsObject;
134 }
135
GetLocalUpdater(napi_env env,napi_callback_info info)136 napi_value GetLocalUpdater(napi_env env, napi_callback_info info)
137 {
138 napi_value jsObject = nullptr;
139 LocalUpdater* localUpdater = CreateJsObject<LocalUpdater>(env, info, g_localUpdaterConstructorRef, jsObject);
140 if (localUpdater == nullptr) {
141 return nullptr;
142 }
143 localUpdater->Init();
144 return jsObject;
145 }
146
CheckNewVersion(napi_env env,napi_callback_info info)147 napi_value CheckNewVersion(napi_env env, napi_callback_info info)
148 {
149 UpdateClient *client = UnwrapJsObject<UpdateClient>(env, info);
150 PARAM_CHECK_NAPI_CALL(env, client != nullptr, return nullptr, "Error get client");
151 return client->CheckNewVersion(env, info);
152 }
153
SetUpgradePolicy(napi_env env,napi_callback_info info)154 napi_value SetUpgradePolicy(napi_env env, napi_callback_info info)
155 {
156 UpdateClient *client = UnwrapJsObject<UpdateClient>(env, info);
157 PARAM_CHECK_NAPI_CALL(env, client != nullptr, return nullptr, "Error get client");
158 return client->SetUpgradePolicy(env, info);
159 }
160
GetUpgradePolicy(napi_env env,napi_callback_info info)161 napi_value GetUpgradePolicy(napi_env env, napi_callback_info info)
162 {
163 UpdateClient *client = UnwrapJsObject<UpdateClient>(env, info);
164 PARAM_CHECK_NAPI_CALL(env, client != nullptr, return nullptr, "Error get client");
165 return client->GetUpgradePolicy(env, info);
166 }
167
Download(napi_env env,napi_callback_info info)168 napi_value Download(napi_env env, napi_callback_info info)
169 {
170 UpdateClient *client = UnwrapJsObject<UpdateClient>(env, info);
171 PARAM_CHECK_NAPI_CALL(env, client != nullptr, return nullptr, "Error get client");
172 return client->Download(env, info);
173 }
174
PauseDownload(napi_env env,napi_callback_info info)175 napi_value PauseDownload(napi_env env, napi_callback_info info)
176 {
177 ENGINE_LOGI("PauseDownload");
178 UpdateClient *client = UnwrapJsObject<UpdateClient>(env, info);
179 PARAM_CHECK_NAPI_CALL(env, client != nullptr, return nullptr, "Error get client");
180 return client->PauseDownload(env, info);
181 }
182
ResumeDownload(napi_env env,napi_callback_info info)183 napi_value ResumeDownload(napi_env env, napi_callback_info info)
184 {
185 ENGINE_LOGI("ResumeDownload");
186 UpdateClient *client = UnwrapJsObject<UpdateClient>(env, info);
187 PARAM_CHECK_NAPI_CALL(env, client != nullptr, return nullptr, "Error get client");
188 return client->ResumeDownload(env, info);
189 }
190
CancelUpgrade(napi_env env,napi_callback_info info)191 napi_value CancelUpgrade(napi_env env, napi_callback_info info)
192 {
193 UpdateClient *client = UnwrapJsObject<UpdateClient>(env, info);
194 PARAM_CHECK_NAPI_CALL(env, client != nullptr, return nullptr, "Error get client");
195 return client->CancelUpgrade(env, info);
196 }
197
Upgrade(napi_env env,napi_callback_info info)198 napi_value Upgrade(napi_env env, napi_callback_info info)
199 {
200 ENGINE_LOGI("Upgrade");
201 UpdateClient *client = UnwrapJsObject<UpdateClient>(env, info);
202 PARAM_CHECK_NAPI_CALL(env, client != nullptr, return nullptr, "Error get client");
203 return client->Upgrade(env, info);
204 }
205
ClearError(napi_env env,napi_callback_info info)206 napi_value ClearError(napi_env env, napi_callback_info info)
207 {
208 ENGINE_LOGI("ClearError");
209 UpdateClient *client = UnwrapJsObject<UpdateClient>(env, info);
210 PARAM_CHECK_NAPI_CALL(env, client != nullptr, return nullptr, "Error get client");
211 return client->ClearError(env, info);
212 }
213
TerminateUpgrade(napi_env env,napi_callback_info info)214 napi_value TerminateUpgrade(napi_env env, napi_callback_info info)
215 {
216 ENGINE_LOGI("TerminateUpgrade");
217 UpdateClient *client = UnwrapJsObject<UpdateClient>(env, info);
218 PARAM_CHECK_NAPI_CALL(env, client != nullptr, return nullptr, "Error get client");
219 return client->TerminateUpgrade(env, info);
220 }
221
GetNewVersionInfo(napi_env env,napi_callback_info info)222 napi_value GetNewVersionInfo(napi_env env, napi_callback_info info)
223 {
224 UpdateClient *client = UnwrapJsObject<UpdateClient>(env, info);
225 PARAM_CHECK_NAPI_CALL(env, client != nullptr, return nullptr, "Error get client");
226 return client->GetNewVersionInfo(env, info);
227 }
228
GetNewVersionDescription(napi_env env,napi_callback_info info)229 napi_value GetNewVersionDescription(napi_env env, napi_callback_info info)
230 {
231 UpdateClient *client = UnwrapJsObject<UpdateClient>(env, info);
232 PARAM_CHECK_NAPI_CALL(env, client != nullptr, return nullptr, "Error get client");
233 return client->GetNewVersionDescription(env, info);
234 }
235
GetCurrentVersionInfo(napi_env env,napi_callback_info info)236 napi_value GetCurrentVersionInfo(napi_env env, napi_callback_info info)
237 {
238 ENGINE_LOGI("GetCurrentVersionInfo");
239 UpdateClient *client = UnwrapJsObject<UpdateClient>(env, info);
240 PARAM_CHECK_NAPI_CALL(env, client != nullptr, return nullptr, "Error get client");
241 return client->GetCurrentVersionInfo(env, info);
242 }
243
GetCurrentVersionDescription(napi_env env,napi_callback_info info)244 napi_value GetCurrentVersionDescription(napi_env env, napi_callback_info info)
245 {
246 UpdateClient *client = UnwrapJsObject<UpdateClient>(env, info);
247 PARAM_CHECK_NAPI_CALL(env, client != nullptr, return nullptr, "Error get client");
248 return client->GetCurrentVersionDescription(env, info);
249 }
250
GetTaskInfo(napi_env env,napi_callback_info info)251 napi_value GetTaskInfo(napi_env env, napi_callback_info info)
252 {
253 ENGINE_LOGI("GetTaskInfo");
254 UpdateClient *client = UnwrapJsObject<UpdateClient>(env, info);
255 PARAM_CHECK_NAPI_CALL(env, client != nullptr, return nullptr, "Error get client");
256 return client->GetTaskInfo(env, info);
257 }
258
DefineClass(napi_env env,napi_value exports,const NativeClass & nativeClass)259 static bool DefineClass(napi_env env, napi_value exports, const NativeClass& nativeClass)
260 {
261 const std::string& className = nativeClass.className;
262 napi_value result = nullptr;
263 napi_status status = napi_define_class(env, className.c_str(), className.size(),
264 nativeClass.constructor, nullptr, nativeClass.descSize, nativeClass.desc, &result);
265 PARAM_CHECK_NAPI_CALL(env, status == napi_ok, return false, "DefineClass error, napi_define_class fail");
266
267 status = napi_set_named_property(env, exports, className.c_str(), result);
268 PARAM_CHECK_NAPI_CALL(env, status == napi_ok, return false, "DefineClass error, napi_set_named_property fail");
269
270 constexpr int32_t refCount = 1; // 新引用的初始引用计数
271 status = napi_create_reference(env, result, refCount, nativeClass.constructorRef);
272 PARAM_CHECK_NAPI_CALL(env, status == napi_ok, return false, "DefineClass error, napi_create_reference fail");
273 return true;
274 }
275
DefineRestorer(napi_env env,napi_value exports)276 static bool DefineRestorer(napi_env env, napi_value exports)
277 {
278 napi_property_descriptor desc[] = {
279 DECLARE_NAPI_FUNCTION(Restorer::Napi::FUNCTION_FACTORY_RESET, Restorer::Napi::FactoryReset)
280 };
281
282 NativeClass nativeClass = {
283 .className = CLASS_NAME_RESTORER,
284 .constructor = JsConstructorRestorer,
285 .constructorRef = &g_restorerConstructorRef,
286 .desc = desc,
287 .descSize = COUNT_OF(desc)
288 };
289 return DefineClass(env, exports, nativeClass);
290 }
291
DefineLocalUpdater(napi_env env,napi_value exports)292 static bool DefineLocalUpdater(napi_env env, napi_value exports)
293 {
294 napi_property_descriptor desc[] = {
295 DECLARE_NAPI_FUNCTION(LocalUpdater::Napi::FUNCTION_VERIFY_UPGRADE_PACKAGE,
296 LocalUpdater::Napi::NapiVerifyUpgradePackage),
297 DECLARE_NAPI_FUNCTION(LocalUpdater::Napi::FUNCTION_APPLY_NEW_VERSION, LocalUpdater::Napi::NapiApplyNewVersion),
298 DECLARE_NAPI_FUNCTION(LocalUpdater::Napi::FUNCTION_ON, LocalUpdater::Napi::NapiOn),
299 DECLARE_NAPI_FUNCTION(LocalUpdater::Napi::FUNCTION_OFF, LocalUpdater::Napi::NapiOff)
300 };
301
302 NativeClass nativeClass = {
303 .className = CLASS_NAME_LOCAL_UPDATER,
304 .constructor = JsConstructorLocalUpdater,
305 .constructorRef = &g_localUpdaterConstructorRef,
306 .desc = desc,
307 .descSize = COUNT_OF(desc)
308 };
309 return DefineClass(env, exports, nativeClass);
310 }
311
DefineUpdateClient(napi_env env,napi_value exports)312 static bool DefineUpdateClient(napi_env env, napi_value exports)
313 {
314 napi_property_descriptor desc[] = {
315 DECLARE_NAPI_FUNCTION("checkNewVersion", CheckNewVersion),
316 DECLARE_NAPI_FUNCTION("getNewVersionInfo", GetNewVersionInfo),
317 DECLARE_NAPI_FUNCTION("getNewVersionDescription", GetNewVersionDescription),
318 DECLARE_NAPI_FUNCTION("getCurrentVersionInfo", GetCurrentVersionInfo),
319 DECLARE_NAPI_FUNCTION("getCurrentVersionDescription", GetCurrentVersionDescription),
320 DECLARE_NAPI_FUNCTION("getTaskInfo", GetTaskInfo),
321 DECLARE_NAPI_FUNCTION("setUpgradePolicy", SetUpgradePolicy),
322 DECLARE_NAPI_FUNCTION("getUpgradePolicy", GetUpgradePolicy),
323 DECLARE_NAPI_FUNCTION("cancel", CancelUpgrade),
324 DECLARE_NAPI_FUNCTION("download", Download),
325 DECLARE_NAPI_FUNCTION("pauseDownload", PauseDownload),
326 DECLARE_NAPI_FUNCTION("resumeDownload", ResumeDownload),
327 DECLARE_NAPI_FUNCTION("upgrade", Upgrade),
328 DECLARE_NAPI_FUNCTION("clearError", ClearError),
329 DECLARE_NAPI_FUNCTION("terminateUpgrade", TerminateUpgrade),
330 DECLARE_NAPI_FUNCTION(UpdateClient::Napi::FUNCTION_ON, UpdateClient::Napi::NapiOn),
331 DECLARE_NAPI_FUNCTION(UpdateClient::Napi::FUNCTION_OFF, UpdateClient::Napi::NapiOff)
332 };
333
334 NativeClass nativeClass = {
335 .className = CLASS_NAME_UPDATE_CLIENT,
336 .constructor = JsConstructor<UpdateClient>,
337 .constructorRef = &g_updateClientConstructorRef,
338 .desc = desc,
339 .descSize = COUNT_OF(desc)
340 };
341 return DefineClass(env, exports, nativeClass);
342 }
343
344 #ifdef UPDATER_UT
UpdateClientInit(napi_env env,napi_value exports)345 napi_value UpdateClientInit(napi_env env, napi_value exports)
346 #else
347 static napi_value UpdateClientInit(napi_env env, napi_value exports)
348 #endif
349 {
350 ENGINE_LOGI("UpdateClientInit");
351 // Registration function
352 napi_property_descriptor desc[] = {
353 DECLARE_NAPI_FUNCTION("getOnlineUpdater", GetOnlineUpdater),
354 DECLARE_NAPI_FUNCTION("getRestorer", GetRestorer),
355 DECLARE_NAPI_FUNCTION("getLocalUpdater", GetLocalUpdater)
356 };
357 napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
358
359 bool ret = DefineUpdateClient(env, exports);
360 PARAM_CHECK_NAPI_CALL(env, ret, return nullptr, "DefineUpdateClient fail");
361 ENGINE_LOGI("DefineUpdateClient success");
362
363 ret = DefineRestorer(env, exports);
364 PARAM_CHECK_NAPI_CALL(env, ret, return nullptr, "DefineRestorer fail");
365 ENGINE_LOGI("DefineRestorer success");
366
367 ret = DefineLocalUpdater(env, exports);
368 PARAM_CHECK_NAPI_CALL(env, ret, return nullptr, "DefineLocalUpdater fail");
369 ENGINE_LOGI("DefineLocalUpdater success");
370
371 DefineProperty::DefineProperties(env, exports);
372 return exports;
373 }
374
375 /*
376 * Module definition
377 */
378 static napi_module g_module = {
379 .nm_version = 1,
380 .nm_flags = 0,
381 .nm_filename = nullptr,
382 .nm_register_func = UpdateClientInit,
383 .nm_modname = "update",
384 .nm_priv = (reinterpret_cast<void*>(0)),
385 .reserved = { 0 }
386 };
387
388 /*
389 * Module registration function
390 */
RegisterModule(void)391 extern "C" __attribute__((constructor)) void RegisterModule(void)
392 {
393 ENGINE_LOGI("RegisterModule");
394 napi_module_register(&g_module);
395 }
396 } // namespace OHOS::UpdateEngine