• 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     napi_value jsObject = nullptr;
116     UpdateClient *client = CreateJsObject<UpdateClient>(env, info, g_updateClientConstructorRef, jsObject);
117     if (client != nullptr) {
118         napi_value result = client->GetOnlineUpdater(env, info);
119         if (result != nullptr) {
120             return jsObject;
121         }
122     }
123     return nullptr;
124 }
125 
GetRestorer(napi_env env,napi_callback_info info)126 napi_value GetRestorer(napi_env env, napi_callback_info info)
127 {
128     napi_value jsObject = nullptr;
129     Restorer* restorer = CreateJsObject<Restorer>(env, info, g_restorerConstructorRef, jsObject);
130     if (restorer == nullptr) {
131         return nullptr;
132     }
133     return jsObject;
134 }
135 
GetLocalUpdater(napi_env env,napi_callback_info info)136 napi_value GetLocalUpdater(napi_env env, napi_callback_info info)
137 {
138     napi_value jsObject = nullptr;
139     LocalUpdater* localUpdater = CreateJsObject<LocalUpdater>(env, info, g_localUpdaterConstructorRef, jsObject);
140     if (localUpdater == nullptr) {
141         return nullptr;
142     }
143     localUpdater->Init();
144     return jsObject;
145 }
146 
CheckNewVersion(napi_env env,napi_callback_info info)147 napi_value CheckNewVersion(napi_env env, napi_callback_info info)
148 {
149     UpdateClient *client = UnwrapJsObject<UpdateClient>(env, info);
150     PARAM_CHECK_NAPI_CALL(env, client != nullptr, return nullptr, "Error get client");
151     return client->CheckNewVersion(env, info);
152 }
153 
SetUpgradePolicy(napi_env env,napi_callback_info info)154 napi_value SetUpgradePolicy(napi_env env, napi_callback_info info)
155 {
156     UpdateClient *client = UnwrapJsObject<UpdateClient>(env, info);
157     PARAM_CHECK_NAPI_CALL(env, client != nullptr, return nullptr, "Error get client");
158     return client->SetUpgradePolicy(env, info);
159 }
160 
GetUpgradePolicy(napi_env env,napi_callback_info info)161 napi_value GetUpgradePolicy(napi_env env, napi_callback_info info)
162 {
163     UpdateClient *client = UnwrapJsObject<UpdateClient>(env, info);
164     PARAM_CHECK_NAPI_CALL(env, client != nullptr, return nullptr, "Error get client");
165     return client->GetUpgradePolicy(env, info);
166 }
167 
Download(napi_env env,napi_callback_info info)168 napi_value Download(napi_env env, napi_callback_info info)
169 {
170     UpdateClient *client = UnwrapJsObject<UpdateClient>(env, info);
171     PARAM_CHECK_NAPI_CALL(env, client != nullptr, return nullptr, "Error get client");
172     return client->Download(env, info);
173 }
174 
PauseDownload(napi_env env,napi_callback_info info)175 napi_value PauseDownload(napi_env env, napi_callback_info info)
176 {
177     ENGINE_LOGI("PauseDownload");
178     UpdateClient *client = UnwrapJsObject<UpdateClient>(env, info);
179     PARAM_CHECK_NAPI_CALL(env, client != nullptr, return nullptr, "Error get client");
180     return client->PauseDownload(env, info);
181 }
182 
ResumeDownload(napi_env env,napi_callback_info info)183 napi_value ResumeDownload(napi_env env, napi_callback_info info)
184 {
185     ENGINE_LOGI("ResumeDownload");
186     UpdateClient *client = UnwrapJsObject<UpdateClient>(env, info);
187     PARAM_CHECK_NAPI_CALL(env, client != nullptr, return nullptr, "Error get client");
188     return client->ResumeDownload(env, info);
189 }
190 
CancelUpgrade(napi_env env,napi_callback_info info)191 napi_value CancelUpgrade(napi_env env, napi_callback_info info)
192 {
193     UpdateClient *client = UnwrapJsObject<UpdateClient>(env, info);
194     PARAM_CHECK_NAPI_CALL(env, client != nullptr, return nullptr, "Error get client");
195     return client->CancelUpgrade(env, info);
196 }
197 
Upgrade(napi_env env,napi_callback_info info)198 napi_value Upgrade(napi_env env, napi_callback_info info)
199 {
200     ENGINE_LOGI("Upgrade");
201     UpdateClient *client = UnwrapJsObject<UpdateClient>(env, info);
202     PARAM_CHECK_NAPI_CALL(env, client != nullptr, return nullptr, "Error get client");
203     return client->Upgrade(env, info);
204 }
205 
ClearError(napi_env env,napi_callback_info info)206 napi_value ClearError(napi_env env, napi_callback_info info)
207 {
208     ENGINE_LOGI("ClearError");
209     UpdateClient *client = UnwrapJsObject<UpdateClient>(env, info);
210     PARAM_CHECK_NAPI_CALL(env, client != nullptr, return nullptr, "Error get client");
211     return client->ClearError(env, info);
212 }
213 
TerminateUpgrade(napi_env env,napi_callback_info info)214 napi_value TerminateUpgrade(napi_env env, napi_callback_info info)
215 {
216     ENGINE_LOGI("TerminateUpgrade");
217     UpdateClient *client = UnwrapJsObject<UpdateClient>(env, info);
218     PARAM_CHECK_NAPI_CALL(env, client != nullptr, return nullptr, "Error get client");
219     return client->TerminateUpgrade(env, info);
220 }
221 
GetNewVersionInfo(napi_env env,napi_callback_info info)222 napi_value GetNewVersionInfo(napi_env env, napi_callback_info info)
223 {
224     UpdateClient *client = UnwrapJsObject<UpdateClient>(env, info);
225     PARAM_CHECK_NAPI_CALL(env, client != nullptr, return nullptr, "Error get client");
226     return client->GetNewVersionInfo(env, info);
227 }
228 
GetNewVersionDescription(napi_env env,napi_callback_info info)229 napi_value GetNewVersionDescription(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->GetNewVersionDescription(env, info);
234 }
235 
GetCurrentVersionInfo(napi_env env,napi_callback_info info)236 napi_value GetCurrentVersionInfo(napi_env env, napi_callback_info info)
237 {
238     ENGINE_LOGI("GetCurrentVersionInfo");
239     UpdateClient *client = UnwrapJsObject<UpdateClient>(env, info);
240     PARAM_CHECK_NAPI_CALL(env, client != nullptr, return nullptr, "Error get client");
241     return client->GetCurrentVersionInfo(env, info);
242 }
243 
GetCurrentVersionDescription(napi_env env,napi_callback_info info)244 napi_value GetCurrentVersionDescription(napi_env env, napi_callback_info info)
245 {
246     UpdateClient *client = UnwrapJsObject<UpdateClient>(env, info);
247     PARAM_CHECK_NAPI_CALL(env, client != nullptr, return nullptr, "Error get client");
248     return client->GetCurrentVersionDescription(env, info);
249 }
250 
GetTaskInfo(napi_env env,napi_callback_info info)251 napi_value GetTaskInfo(napi_env env, napi_callback_info info)
252 {
253     ENGINE_LOGI("GetTaskInfo");
254     UpdateClient *client = UnwrapJsObject<UpdateClient>(env, info);
255     PARAM_CHECK_NAPI_CALL(env, client != nullptr, return nullptr, "Error get client");
256     return client->GetTaskInfo(env, info);
257 }
258 
DefineClass(napi_env env,napi_value exports,const NativeClass & nativeClass)259 static bool DefineClass(napi_env env, napi_value exports, const NativeClass& nativeClass)
260 {
261     const std::string& className = nativeClass.className;
262     napi_value result = nullptr;
263     napi_status status = napi_define_class(env, className.c_str(), className.size(),
264         nativeClass.constructor, nullptr, nativeClass.descSize, nativeClass.desc, &result);
265     PARAM_CHECK_NAPI_CALL(env, status == napi_ok, return false, "DefineClass error, napi_define_class fail");
266 
267     status = napi_set_named_property(env, exports, className.c_str(), result);
268     PARAM_CHECK_NAPI_CALL(env, status == napi_ok, return false, "DefineClass error, napi_set_named_property fail");
269 
270     constexpr int32_t refCount = 1; // 新引用的初始引用计数
271     status = napi_create_reference(env, result, refCount, nativeClass.constructorRef);
272     PARAM_CHECK_NAPI_CALL(env, status == napi_ok, return false, "DefineClass error, napi_create_reference fail");
273     return true;
274 }
275 
DefineRestorer(napi_env env,napi_value exports)276 static bool DefineRestorer(napi_env env, napi_value exports)
277 {
278     napi_property_descriptor desc[] = {
279         DECLARE_NAPI_FUNCTION(Restorer::Napi::FUNCTION_FACTORY_RESET, Restorer::Napi::FactoryReset)
280     };
281 
282     NativeClass nativeClass = {
283         .className = CLASS_NAME_RESTORER,
284         .constructor = JsConstructorRestorer,
285         .constructorRef = &g_restorerConstructorRef,
286         .desc = desc,
287         .descSize = COUNT_OF(desc)
288     };
289     return DefineClass(env, exports, nativeClass);
290 }
291 
DefineLocalUpdater(napi_env env,napi_value exports)292 static bool DefineLocalUpdater(napi_env env, napi_value exports)
293 {
294     napi_property_descriptor desc[] = {
295         DECLARE_NAPI_FUNCTION(LocalUpdater::Napi::FUNCTION_VERIFY_UPGRADE_PACKAGE,
296             LocalUpdater::Napi::NapiVerifyUpgradePackage),
297         DECLARE_NAPI_FUNCTION(LocalUpdater::Napi::FUNCTION_APPLY_NEW_VERSION, LocalUpdater::Napi::NapiApplyNewVersion),
298         DECLARE_NAPI_FUNCTION(LocalUpdater::Napi::FUNCTION_ON, LocalUpdater::Napi::NapiOn),
299         DECLARE_NAPI_FUNCTION(LocalUpdater::Napi::FUNCTION_OFF, LocalUpdater::Napi::NapiOff)
300     };
301 
302     NativeClass nativeClass = {
303         .className = CLASS_NAME_LOCAL_UPDATER,
304         .constructor = JsConstructorLocalUpdater,
305         .constructorRef = &g_localUpdaterConstructorRef,
306         .desc = desc,
307         .descSize = COUNT_OF(desc)
308     };
309     return DefineClass(env, exports, nativeClass);
310 }
311 
DefineUpdateClient(napi_env env,napi_value exports)312 static bool DefineUpdateClient(napi_env env, napi_value exports)
313 {
314     napi_property_descriptor desc[] = {
315         DECLARE_NAPI_FUNCTION("checkNewVersion", CheckNewVersion),
316         DECLARE_NAPI_FUNCTION("getNewVersionInfo", GetNewVersionInfo),
317         DECLARE_NAPI_FUNCTION("getNewVersionDescription", GetNewVersionDescription),
318         DECLARE_NAPI_FUNCTION("getCurrentVersionInfo", GetCurrentVersionInfo),
319         DECLARE_NAPI_FUNCTION("getCurrentVersionDescription", GetCurrentVersionDescription),
320         DECLARE_NAPI_FUNCTION("getTaskInfo", GetTaskInfo),
321         DECLARE_NAPI_FUNCTION("setUpgradePolicy", SetUpgradePolicy),
322         DECLARE_NAPI_FUNCTION("getUpgradePolicy", GetUpgradePolicy),
323         DECLARE_NAPI_FUNCTION("cancel", CancelUpgrade),
324         DECLARE_NAPI_FUNCTION("download", Download),
325         DECLARE_NAPI_FUNCTION("pauseDownload", PauseDownload),
326         DECLARE_NAPI_FUNCTION("resumeDownload", ResumeDownload),
327         DECLARE_NAPI_FUNCTION("upgrade", Upgrade),
328         DECLARE_NAPI_FUNCTION("clearError", ClearError),
329         DECLARE_NAPI_FUNCTION("terminateUpgrade", TerminateUpgrade),
330         DECLARE_NAPI_FUNCTION(UpdateClient::Napi::FUNCTION_ON, UpdateClient::Napi::NapiOn),
331         DECLARE_NAPI_FUNCTION(UpdateClient::Napi::FUNCTION_OFF, UpdateClient::Napi::NapiOff)
332     };
333 
334     NativeClass nativeClass = {
335         .className = CLASS_NAME_UPDATE_CLIENT,
336         .constructor = JsConstructor<UpdateClient>,
337         .constructorRef = &g_updateClientConstructorRef,
338         .desc = desc,
339         .descSize = COUNT_OF(desc)
340     };
341     return DefineClass(env, exports, nativeClass);
342 }
343 
344 #ifdef UPDATER_UT
UpdateClientInit(napi_env env,napi_value exports)345 napi_value UpdateClientInit(napi_env env, napi_value exports)
346 #else
347 static napi_value UpdateClientInit(napi_env env, napi_value exports)
348 #endif
349 {
350     ENGINE_LOGI("UpdateClientInit");
351     // Registration function
352     napi_property_descriptor desc[] = {
353         DECLARE_NAPI_FUNCTION("getOnlineUpdater", GetOnlineUpdater),
354         DECLARE_NAPI_FUNCTION("getRestorer", GetRestorer),
355         DECLARE_NAPI_FUNCTION("getLocalUpdater", GetLocalUpdater)
356     };
357     napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
358 
359     bool ret = DefineUpdateClient(env, exports);
360     PARAM_CHECK_NAPI_CALL(env, ret, return nullptr, "DefineUpdateClient fail");
361     ENGINE_LOGI("DefineUpdateClient success");
362 
363     ret = DefineRestorer(env, exports);
364     PARAM_CHECK_NAPI_CALL(env, ret, return nullptr, "DefineRestorer fail");
365     ENGINE_LOGI("DefineRestorer success");
366 
367     ret = DefineLocalUpdater(env, exports);
368     PARAM_CHECK_NAPI_CALL(env, ret, return nullptr, "DefineLocalUpdater fail");
369     ENGINE_LOGI("DefineLocalUpdater success");
370 
371     DefineProperty::DefineProperties(env, exports);
372     return exports;
373 }
374 
375 /*
376  * Module definition
377  */
378 static napi_module g_module = {
379     .nm_version = 1,
380     .nm_flags = 0,
381     .nm_filename = nullptr,
382     .nm_register_func = UpdateClientInit,
383     .nm_modname = "update",
384     .nm_priv = (reinterpret_cast<void*>(0)),
385     .reserved = { 0 }
386 };
387 
388 /*
389  * Module registration function
390  */
RegisterModule(void)391 extern "C" __attribute__((constructor)) void RegisterModule(void)
392 {
393     ENGINE_LOGI("RegisterModule");
394     napi_module_register(&g_module);
395 }
396 } // namespace OHOS::UpdateEngine