• 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 
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