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