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