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 bool isCallerValid = NapiCommonUtils::IsCallerValid();
116 PARAM_CHECK_NAPI_CALL(env, isCallerValid, NapiCommonUtils::NapiThrowNotSystemAppError(env);
117 return nullptr, "Failed to GetOnlineUpdater");
118
119 napi_value jsObject = nullptr;
120 UpdateClient *client = CreateJsObject<UpdateClient>(env, info, g_updateClientConstructorRef, jsObject);
121 if (client != nullptr) {
122 napi_value result = client->GetOnlineUpdater(env, info);
123 if (result != nullptr) {
124 return jsObject;
125 }
126 }
127 return nullptr;
128 }
129
GetRestorer(napi_env env,napi_callback_info info)130 napi_value GetRestorer(napi_env env, napi_callback_info info)
131 {
132 bool isCallerValid = NapiCommonUtils::IsCallerValid();
133 PARAM_CHECK_NAPI_CALL(env, isCallerValid, NapiCommonUtils::NapiThrowNotSystemAppError(env);
134 return nullptr, "Failed to GetRestorer");
135
136 napi_value jsObject = nullptr;
137 Restorer* restorer = CreateJsObject<Restorer>(env, info, g_restorerConstructorRef, jsObject);
138 if (restorer == nullptr) {
139 return nullptr;
140 }
141 return jsObject;
142 }
143
GetLocalUpdater(napi_env env,napi_callback_info info)144 napi_value GetLocalUpdater(napi_env env, napi_callback_info info)
145 {
146 bool isCallerValid = NapiCommonUtils::IsCallerValid();
147 PARAM_CHECK_NAPI_CALL(env, isCallerValid, NapiCommonUtils::NapiThrowNotSystemAppError(env);
148 return nullptr, "Failed to GetLocalUpdater");
149
150 napi_value jsObject = nullptr;
151 LocalUpdater* localUpdater = CreateJsObject<LocalUpdater>(env, info, g_localUpdaterConstructorRef, jsObject);
152 if (localUpdater == nullptr) {
153 return nullptr;
154 }
155 localUpdater->Init();
156 return jsObject;
157 }
158
CheckNewVersion(napi_env env,napi_callback_info info)159 napi_value CheckNewVersion(napi_env env, napi_callback_info info)
160 {
161 UpdateClient *client = UnwrapJsObject<UpdateClient>(env, info);
162 PARAM_CHECK_NAPI_CALL(env, client != nullptr, return nullptr, "Error get client");
163 return client->CheckNewVersion(env, info);
164 }
165
SetUpgradePolicy(napi_env env,napi_callback_info info)166 napi_value SetUpgradePolicy(napi_env env, napi_callback_info info)
167 {
168 UpdateClient *client = UnwrapJsObject<UpdateClient>(env, info);
169 PARAM_CHECK_NAPI_CALL(env, client != nullptr, return nullptr, "Error get client");
170 return client->SetUpgradePolicy(env, info);
171 }
172
GetUpgradePolicy(napi_env env,napi_callback_info info)173 napi_value GetUpgradePolicy(napi_env env, napi_callback_info info)
174 {
175 UpdateClient *client = UnwrapJsObject<UpdateClient>(env, info);
176 PARAM_CHECK_NAPI_CALL(env, client != nullptr, return nullptr, "Error get client");
177 return client->GetUpgradePolicy(env, info);
178 }
179
Download(napi_env env,napi_callback_info info)180 napi_value Download(napi_env env, napi_callback_info info)
181 {
182 UpdateClient *client = UnwrapJsObject<UpdateClient>(env, info);
183 PARAM_CHECK_NAPI_CALL(env, client != nullptr, return nullptr, "Error get client");
184 return client->Download(env, info);
185 }
186
PauseDownload(napi_env env,napi_callback_info info)187 napi_value PauseDownload(napi_env env, napi_callback_info info)
188 {
189 ENGINE_LOGI("PauseDownload");
190 UpdateClient *client = UnwrapJsObject<UpdateClient>(env, info);
191 PARAM_CHECK_NAPI_CALL(env, client != nullptr, return nullptr, "Error get client");
192 return client->PauseDownload(env, info);
193 }
194
ResumeDownload(napi_env env,napi_callback_info info)195 napi_value ResumeDownload(napi_env env, napi_callback_info info)
196 {
197 ENGINE_LOGI("ResumeDownload");
198 UpdateClient *client = UnwrapJsObject<UpdateClient>(env, info);
199 PARAM_CHECK_NAPI_CALL(env, client != nullptr, return nullptr, "Error get client");
200 return client->ResumeDownload(env, info);
201 }
202
CancelUpgrade(napi_env env,napi_callback_info info)203 napi_value CancelUpgrade(napi_env env, napi_callback_info info)
204 {
205 UpdateClient *client = UnwrapJsObject<UpdateClient>(env, info);
206 PARAM_CHECK_NAPI_CALL(env, client != nullptr, return nullptr, "Error get client");
207 return client->CancelUpgrade(env, info);
208 }
209
Upgrade(napi_env env,napi_callback_info info)210 napi_value Upgrade(napi_env env, napi_callback_info info)
211 {
212 ENGINE_LOGI("Upgrade");
213 UpdateClient *client = UnwrapJsObject<UpdateClient>(env, info);
214 PARAM_CHECK_NAPI_CALL(env, client != nullptr, return nullptr, "Error get client");
215 return client->Upgrade(env, info);
216 }
217
ClearError(napi_env env,napi_callback_info info)218 napi_value ClearError(napi_env env, napi_callback_info info)
219 {
220 ENGINE_LOGI("ClearError");
221 UpdateClient *client = UnwrapJsObject<UpdateClient>(env, info);
222 PARAM_CHECK_NAPI_CALL(env, client != nullptr, return nullptr, "Error get client");
223 return client->ClearError(env, info);
224 }
225
TerminateUpgrade(napi_env env,napi_callback_info info)226 napi_value TerminateUpgrade(napi_env env, napi_callback_info info)
227 {
228 ENGINE_LOGI("TerminateUpgrade");
229 UpdateClient *client = UnwrapJsObject<UpdateClient>(env, info);
230 PARAM_CHECK_NAPI_CALL(env, client != nullptr, return nullptr, "Error get client");
231 return client->TerminateUpgrade(env, info);
232 }
233
GetNewVersionInfo(napi_env env,napi_callback_info info)234 napi_value GetNewVersionInfo(napi_env env, napi_callback_info info)
235 {
236 UpdateClient *client = UnwrapJsObject<UpdateClient>(env, info);
237 PARAM_CHECK_NAPI_CALL(env, client != nullptr, return nullptr, "Error get client");
238 return client->GetNewVersionInfo(env, info);
239 }
240
GetNewVersionDescription(napi_env env,napi_callback_info info)241 napi_value GetNewVersionDescription(napi_env env, napi_callback_info info)
242 {
243 UpdateClient *client = UnwrapJsObject<UpdateClient>(env, info);
244 PARAM_CHECK_NAPI_CALL(env, client != nullptr, return nullptr, "Error get client");
245 return client->GetNewVersionDescription(env, info);
246 }
247
GetCurrentVersionInfo(napi_env env,napi_callback_info info)248 napi_value GetCurrentVersionInfo(napi_env env, napi_callback_info info)
249 {
250 ENGINE_LOGI("GetCurrentVersionInfo");
251 UpdateClient *client = UnwrapJsObject<UpdateClient>(env, info);
252 PARAM_CHECK_NAPI_CALL(env, client != nullptr, return nullptr, "Error get client");
253 return client->GetCurrentVersionInfo(env, info);
254 }
255
GetCurrentVersionDescription(napi_env env,napi_callback_info info)256 napi_value GetCurrentVersionDescription(napi_env env, napi_callback_info info)
257 {
258 UpdateClient *client = UnwrapJsObject<UpdateClient>(env, info);
259 PARAM_CHECK_NAPI_CALL(env, client != nullptr, return nullptr, "Error get client");
260 return client->GetCurrentVersionDescription(env, info);
261 }
262
GetTaskInfo(napi_env env,napi_callback_info info)263 napi_value GetTaskInfo(napi_env env, napi_callback_info info)
264 {
265 ENGINE_LOGI("GetTaskInfo");
266 UpdateClient *client = UnwrapJsObject<UpdateClient>(env, info);
267 PARAM_CHECK_NAPI_CALL(env, client != nullptr, return nullptr, "Error get client");
268 return client->GetTaskInfo(env, info);
269 }
270
DefineClass(napi_env env,napi_value exports,const NativeClass & nativeClass)271 static bool DefineClass(napi_env env, napi_value exports, const NativeClass& nativeClass)
272 {
273 const std::string& className = nativeClass.className;
274 napi_value result = nullptr;
275 napi_status status = napi_define_class(env, className.c_str(), className.size(),
276 nativeClass.constructor, nullptr, nativeClass.descSize, nativeClass.desc, &result);
277 PARAM_CHECK_NAPI_CALL(env, status == napi_ok, return false, "DefineClass error, napi_define_class fail");
278
279 status = napi_set_named_property(env, exports, className.c_str(), result);
280 PARAM_CHECK_NAPI_CALL(env, status == napi_ok, return false, "DefineClass error, napi_set_named_property fail");
281
282 constexpr int32_t refCount = 1; // 新引用的初始引用计数
283 status = napi_create_reference(env, result, refCount, nativeClass.constructorRef);
284 PARAM_CHECK_NAPI_CALL(env, status == napi_ok, return false, "DefineClass error, napi_create_reference fail");
285 return true;
286 }
287
DefineRestorer(napi_env env,napi_value exports)288 static bool DefineRestorer(napi_env env, napi_value exports)
289 {
290 napi_property_descriptor desc[] = {
291 DECLARE_NAPI_FUNCTION(Restorer::Napi::FUNCTION_FACTORY_RESET, Restorer::Napi::FactoryReset)
292 };
293
294 NativeClass nativeClass = {
295 .className = CLASS_NAME_RESTORER,
296 .constructor = JsConstructorRestorer,
297 .constructorRef = &g_restorerConstructorRef,
298 .desc = desc,
299 .descSize = COUNT_OF(desc)
300 };
301 return DefineClass(env, exports, nativeClass);
302 }
303
DefineLocalUpdater(napi_env env,napi_value exports)304 static bool DefineLocalUpdater(napi_env env, napi_value exports)
305 {
306 napi_property_descriptor desc[] = {
307 DECLARE_NAPI_FUNCTION(LocalUpdater::Napi::FUNCTION_VERIFY_UPGRADE_PACKAGE,
308 LocalUpdater::Napi::NapiVerifyUpgradePackage),
309 DECLARE_NAPI_FUNCTION(LocalUpdater::Napi::FUNCTION_APPLY_NEW_VERSION, LocalUpdater::Napi::NapiApplyNewVersion),
310 DECLARE_NAPI_FUNCTION(LocalUpdater::Napi::FUNCTION_ON, LocalUpdater::Napi::NapiOn),
311 DECLARE_NAPI_FUNCTION(LocalUpdater::Napi::FUNCTION_OFF, LocalUpdater::Napi::NapiOff)
312 };
313
314 NativeClass nativeClass = {
315 .className = CLASS_NAME_LOCAL_UPDATER,
316 .constructor = JsConstructorLocalUpdater,
317 .constructorRef = &g_localUpdaterConstructorRef,
318 .desc = desc,
319 .descSize = COUNT_OF(desc)
320 };
321 return DefineClass(env, exports, nativeClass);
322 }
323
DefineUpdateClient(napi_env env,napi_value exports)324 static bool DefineUpdateClient(napi_env env, napi_value exports)
325 {
326 napi_property_descriptor desc[] = {
327 DECLARE_NAPI_FUNCTION("checkNewVersion", CheckNewVersion),
328 DECLARE_NAPI_FUNCTION("getNewVersionInfo", GetNewVersionInfo),
329 DECLARE_NAPI_FUNCTION("getNewVersionDescription", GetNewVersionDescription),
330 DECLARE_NAPI_FUNCTION("getCurrentVersionInfo", GetCurrentVersionInfo),
331 DECLARE_NAPI_FUNCTION("getCurrentVersionDescription", GetCurrentVersionDescription),
332 DECLARE_NAPI_FUNCTION("getTaskInfo", GetTaskInfo),
333 DECLARE_NAPI_FUNCTION("setUpgradePolicy", SetUpgradePolicy),
334 DECLARE_NAPI_FUNCTION("getUpgradePolicy", GetUpgradePolicy),
335 DECLARE_NAPI_FUNCTION("cancel", CancelUpgrade),
336 DECLARE_NAPI_FUNCTION("download", Download),
337 DECLARE_NAPI_FUNCTION("pauseDownload", PauseDownload),
338 DECLARE_NAPI_FUNCTION("resumeDownload", ResumeDownload),
339 DECLARE_NAPI_FUNCTION("upgrade", Upgrade),
340 DECLARE_NAPI_FUNCTION("clearError", ClearError),
341 DECLARE_NAPI_FUNCTION("terminateUpgrade", TerminateUpgrade),
342 DECLARE_NAPI_FUNCTION(UpdateClient::Napi::FUNCTION_ON, UpdateClient::Napi::NapiOn),
343 DECLARE_NAPI_FUNCTION(UpdateClient::Napi::FUNCTION_OFF, UpdateClient::Napi::NapiOff)
344 };
345
346 NativeClass nativeClass = {
347 .className = CLASS_NAME_UPDATE_CLIENT,
348 .constructor = JsConstructor<UpdateClient>,
349 .constructorRef = &g_updateClientConstructorRef,
350 .desc = desc,
351 .descSize = COUNT_OF(desc)
352 };
353 return DefineClass(env, exports, nativeClass);
354 }
355
356 #ifdef UPDATER_UT
UpdateClientInit(napi_env env,napi_value exports)357 napi_value UpdateClientInit(napi_env env, napi_value exports)
358 #else
359 static napi_value UpdateClientInit(napi_env env, napi_value exports)
360 #endif
361 {
362 ENGINE_LOGI("UpdateClientInit");
363 // Registration function
364 napi_property_descriptor desc[] = {
365 DECLARE_NAPI_FUNCTION("getOnlineUpdater", GetOnlineUpdater),
366 DECLARE_NAPI_FUNCTION("getRestorer", GetRestorer),
367 DECLARE_NAPI_FUNCTION("getLocalUpdater", GetLocalUpdater)
368 };
369 napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
370
371 bool ret = DefineUpdateClient(env, exports);
372 PARAM_CHECK_NAPI_CALL(env, ret, return nullptr, "DefineUpdateClient fail");
373 ENGINE_LOGI("DefineUpdateClient success");
374
375 ret = DefineRestorer(env, exports);
376 PARAM_CHECK_NAPI_CALL(env, ret, return nullptr, "DefineRestorer fail");
377 ENGINE_LOGI("DefineRestorer success");
378
379 ret = DefineLocalUpdater(env, exports);
380 PARAM_CHECK_NAPI_CALL(env, ret, return nullptr, "DefineLocalUpdater fail");
381 ENGINE_LOGI("DefineLocalUpdater success");
382
383 DefineProperty::DefineProperties(env, exports);
384 return exports;
385 }
386
387 /*
388 * Module definition
389 */
390 static napi_module g_module = {
391 .nm_version = 1,
392 .nm_flags = 0,
393 .nm_filename = nullptr,
394 .nm_register_func = UpdateClientInit,
395 .nm_modname = "update",
396 .nm_priv = (reinterpret_cast<void*>(0)),
397 .reserved = { 0 }
398 };
399
400 /*
401 * Module registration function
402 */
RegisterModule(void)403 extern "C" __attribute__((constructor)) void RegisterModule(void)
404 {
405 ENGINE_LOGI("RegisterModule");
406 napi_module_register(&g_module);
407 }
408 } // namespace OHOS::UpdateEngine