• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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