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