1 /*
2 * Copyright (C) 2023 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 #define MLOG_TAG "MediaLibraryBackupNapi"
17
18 #include <napi_base_context.h>
19 #include "medialibrary_backup_napi.h"
20 #include "application_context.h"
21 #include "backup_restore_service.h"
22 #include "js_native_api.h"
23 #include "medialibrary_client_errno.h"
24 #include "medialibrary_errno.h"
25 #include "medialibrary_napi_log.h"
26 #include "medialibrary_napi_utils.h"
27
28 namespace OHOS {
29 namespace Media {
30
31 using RestoreBlock = struct {
32 napi_env env;
33 std::weak_ptr<OHOS::AbilityRuntime::Context> context;
34 RestoreInfo restoreInfo;
35 napi_deferred nativeDeferred;
36 };
37
38 using RestoreExBlock = struct {
39 napi_env env;
40 std::weak_ptr<OHOS::AbilityRuntime::Context> context;
41 RestoreInfo restoreInfo;
42 std::string restoreExInfo;
43 napi_deferred nativeDeferred;
44 };
45
46 using BackupBlock = struct {
47 napi_env env;
48 int32_t sceneCode;
49 std::string galleryAppName;
50 std::string mediaAppName;
51 napi_deferred nativeDeferred;
52 };
53
54 using BackupExBlock = struct {
55 napi_env env;
56 int32_t sceneCode;
57 std::string galleryAppName;
58 std::string mediaAppName;
59 napi_deferred nativeDeferred;
60 std::string backupInfo;
61 std::string backupExInfo;
62 };
63
Init(napi_env env,napi_value exports)64 napi_value MediaLibraryBackupNapi::Init(napi_env env, napi_value exports)
65 {
66 NAPI_INFO_LOG("Init, MediaLibraryBackupNapi has been used.");
67 napi_property_descriptor media_library_properties[] = {
68 DECLARE_NAPI_FUNCTION("startRestore", JSStartRestore),
69 DECLARE_NAPI_FUNCTION("startRestoreEx", JSStartRestoreEx),
70 DECLARE_NAPI_FUNCTION("getBackupInfo", JSGetBackupInfo),
71 DECLARE_NAPI_FUNCTION("getProgressInfo", JSGetProgressInfo),
72 DECLARE_NAPI_FUNCTION("startBackup", JSStartBackup),
73 DECLARE_NAPI_FUNCTION("startBackupEx", JSStartBackupEx),
74 DECLARE_NAPI_FUNCTION("release", JSRelease),
75 };
76
77 NAPI_CALL(env, napi_define_properties(env, exports, sizeof(media_library_properties) /
78 sizeof(media_library_properties[0]), media_library_properties));
79 return exports;
80 }
81
GetIntFromParams(napi_env env,const napi_value args[],size_t index)82 static int32_t GetIntFromParams(napi_env env, const napi_value args[], size_t index)
83 {
84 int32_t result = -1;
85 napi_valuetype valueType = napi_undefined;
86 if (napi_typeof(env, args[index], &valueType) != napi_ok || valueType != napi_number) {
87 NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
88 return result;
89 }
90 napi_get_value_int32(env, args[index], &result);
91 return result;
92 }
93
GetStringFromParams(napi_env env,const napi_value args[],size_t index)94 static std::string GetStringFromParams(napi_env env, const napi_value args[], size_t index)
95 {
96 napi_valuetype valueType = napi_undefined;
97 if (napi_typeof(env, args[index], &valueType) != napi_ok || valueType != napi_string) {
98 NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
99 return "";
100 }
101
102 size_t resultLength;
103 napi_get_value_string_utf8(env, args[index], nullptr, 0, &resultLength);
104 std::string result(resultLength, '\0');
105 napi_get_value_string_utf8(env, args[index], &result[0], resultLength + 1, &resultLength);
106 return result;
107 }
108
CheckPermission(void)109 static int32_t CheckPermission(void)
110 {
111 auto context = AbilityRuntime::Context::GetApplicationContext();
112 if (context == nullptr) {
113 NAPI_ERR_LOG("Failed to get context");
114 return E_FAIL;
115 }
116 std::string bundleName = context->GetBundleName();
117 if (bundleName.compare(BUNDLE_NAME) != 0) {
118 NAPI_ERR_LOG("bundleName is invalid, %{public}s", bundleName.c_str());
119 return E_FAIL;
120 }
121 return E_OK;
122 }
123
UvQueueWork(uv_loop_s * loop,uv_work_t * work)124 void MediaLibraryBackupNapi::UvQueueWork(uv_loop_s *loop, uv_work_t *work)
125 {
126 uv_queue_work(loop, work, [](uv_work_t *work) {
127 RestoreBlock *block = reinterpret_cast<RestoreBlock *> (work->data);
128 if (block == nullptr) {
129 delete work;
130 return;
131 }
132 BackupRestoreService::GetInstance().StartRestore(block->context.lock(), block->restoreInfo);
133 }, [](uv_work_t *work, int _status) {
134 RestoreBlock *block = reinterpret_cast<RestoreBlock *> (work->data);
135 napi_handle_scope scope = nullptr;
136 napi_open_handle_scope(block->env, &scope);
137 if (scope == nullptr) {
138 delete work;
139 return;
140 }
141 napi_value resultCode = nullptr;
142 napi_create_int32(block->env, 1, &resultCode);
143 napi_resolve_deferred(block->env, block->nativeDeferred, resultCode);
144 napi_close_handle_scope(block->env, scope);
145 delete block;
146 delete work;
147 });
148 }
149
ParseContext(const napi_env & env,const napi_value & input,std::shared_ptr<OHOS::AbilityRuntime::Context> & context)150 bool ParseContext(const napi_env &env, const napi_value &input,
151 std::shared_ptr<OHOS::AbilityRuntime::Context> &context)
152 {
153 bool isStageMode = false;
154 napi_status status = OHOS::AbilityRuntime::IsStageContext(env, input, isStageMode);
155 if (status != napi_ok) {
156 NAPI_ERR_LOG("parse context status error, status:%{public}d", status);
157 return false;
158 }
159 if (!isStageMode) {
160 NAPI_ERR_LOG("parse context failed, not stage context");
161 return false;
162 }
163 context = OHOS::AbilityRuntime::GetStageModeContext(env, input);
164 if (context == nullptr) {
165 NAPI_ERR_LOG("parse context failed, context is null");
166 return false;
167 }
168
169 return true;
170 }
171
JSStartRestore(napi_env env,napi_callback_info info)172 napi_value MediaLibraryBackupNapi::JSStartRestore(napi_env env, napi_callback_info info)
173 {
174 napi_value result = nullptr;
175 if (CheckPermission() != E_OK) {
176 return result;
177 }
178
179 size_t argc = ARGS_FIVE;
180 napi_value argv[ARGS_FIVE] = {0};
181 napi_value thisVar = nullptr;
182
183 GET_JS_ARGS(env, info, argc, argv, thisVar);
184 NAPI_ASSERT(env, (argc == ARGS_FIVE), "requires 5 parameters");
185 napi_get_undefined(env, &result);
186
187 // get ability context
188 std::shared_ptr<OHOS::AbilityRuntime::Context> context;
189 if (!ParseContext(env, argv[PARAM0], context)) {
190 return result;
191 }
192 RestoreInfo restoreInfo;
193 restoreInfo.sceneCode = GetIntFromParams(env, argv, PARAM1);
194 restoreInfo.galleryAppName = GetStringFromParams(env, argv, PARAM2);
195 restoreInfo.mediaAppName = GetStringFromParams(env, argv, PARAM3);
196 restoreInfo.backupDir = GetStringFromParams(env, argv, PARAM4);
197 NAPI_INFO_LOG("StartRestore, sceneCode = %{public}d", restoreInfo.sceneCode);
198
199 if (restoreInfo.sceneCode < 0) {
200 NAPI_ERR_LOG("Parameters error, sceneCode = %{public}d", restoreInfo.sceneCode);
201 return result;
202 }
203 uv_loop_s *loop = nullptr;
204 napi_get_uv_event_loop(env, &loop);
205 uv_work_t *work = new (std::nothrow) uv_work_t;
206 if (work == nullptr) {
207 NAPI_ERR_LOG("Failed to new uv_work");
208 return result;
209 }
210 napi_deferred nativeDeferred = nullptr;
211 napi_create_promise(env, &nativeDeferred, &result);
212 RestoreBlock *block = new (std::nothrow) RestoreBlock { env, context, restoreInfo, nativeDeferred };
213 if (block == nullptr) {
214 NAPI_ERR_LOG("Failed to new block");
215 delete work;
216 return result;
217 }
218 work->data = reinterpret_cast<void *>(block);
219 UvQueueWork(loop, work);
220 return result;
221 }
222
UvQueueWorkEx(uv_loop_s * loop,uv_work_t * work)223 void MediaLibraryBackupNapi::UvQueueWorkEx(uv_loop_s *loop, uv_work_t *work)
224 {
225 uv_queue_work(loop, work, [](uv_work_t *work) {
226 RestoreExBlock *block = reinterpret_cast<RestoreExBlock *> (work->data);
227 BackupRestoreService::GetInstance().StartRestoreEx(block->context.lock(), block->restoreInfo,
228 block->restoreExInfo);
229 }, [](uv_work_t *work, int _status) {
230 RestoreExBlock *block = reinterpret_cast<RestoreExBlock *> (work->data);
231 if (block == nullptr) {
232 delete work;
233 return;
234 }
235 napi_handle_scope scope = nullptr;
236 napi_open_handle_scope(block->env, &scope);
237 if (scope == nullptr) {
238 delete work;
239 return;
240 }
241 napi_value restoreExResult = nullptr;
242 napi_create_string_utf8(block->env, block->restoreExInfo.c_str(), NAPI_AUTO_LENGTH, &restoreExResult);
243 napi_resolve_deferred(block->env, block->nativeDeferred, restoreExResult);
244 napi_close_handle_scope(block->env, scope);
245 delete block;
246 delete work;
247 });
248 }
249
JSStartRestoreEx(napi_env env,napi_callback_info info)250 napi_value MediaLibraryBackupNapi::JSStartRestoreEx(napi_env env, napi_callback_info info)
251 {
252 napi_value result = nullptr;
253 if (CheckPermission() != E_OK) {
254 return result;
255 }
256
257 size_t argc = ARGS_SIX;
258 napi_value argv[ARGS_SIX] = {0};
259 napi_value thisVar = nullptr;
260
261 GET_JS_ARGS(env, info, argc, argv, thisVar);
262 NAPI_ASSERT(env, (argc == ARGS_SIX), "requires 6 parameters");
263 napi_get_undefined(env, &result);
264 // get ability context
265 std::shared_ptr<OHOS::AbilityRuntime::Context> context;
266 if (!ParseContext(env, argv[PARAM0], context)) {
267 return result;
268 }
269 RestoreInfo restoreInfo;
270 restoreInfo.sceneCode = GetIntFromParams(env, argv, PARAM1);
271 restoreInfo.galleryAppName = GetStringFromParams(env, argv, PARAM2);
272 restoreInfo.mediaAppName = GetStringFromParams(env, argv, PARAM3);
273 restoreInfo.backupDir = GetStringFromParams(env, argv, PARAM4);
274 restoreInfo.bundleInfo = GetStringFromParams(env, argv, PARAM5);
275 std::string restoreExInfo;
276 NAPI_INFO_LOG("StartRestoreEx, sceneCode = %{public}d", restoreInfo.sceneCode);
277 if (restoreInfo.sceneCode < 0) {
278 NAPI_INFO_LOG("Parameters error, sceneCode = %{public}d", restoreInfo.sceneCode);
279 return result;
280 }
281 uv_loop_s *loop = nullptr;
282 napi_get_uv_event_loop(env, &loop);
283 uv_work_t *work = new (std::nothrow) uv_work_t;
284 if (work == nullptr) {
285 NAPI_ERR_LOG("Failed to new uv_work");
286 return result;
287 }
288 napi_deferred nativeDeferred = nullptr;
289 napi_create_promise(env, &nativeDeferred, &result);
290 RestoreExBlock *block = new (std::nothrow) RestoreExBlock {
291 env, context, restoreInfo, restoreExInfo, nativeDeferred };
292 if (block == nullptr) {
293 NAPI_ERR_LOG("Failed to new block");
294 delete work;
295 return result;
296 }
297 work->data = reinterpret_cast<void *>(block);
298 UvQueueWorkEx(loop, work);
299 return result;
300 }
301
JSGetBackupInfo(napi_env env,napi_callback_info info)302 napi_value MediaLibraryBackupNapi::JSGetBackupInfo(napi_env env, napi_callback_info info)
303 {
304 napi_value result = nullptr;
305 if (CheckPermission() != E_OK) {
306 return result;
307 }
308
309 size_t argc = ARGS_ONE;
310 napi_value argv[ARGS_ONE] = {0};
311 napi_value thisVar = nullptr;
312
313 GET_JS_ARGS(env, info, argc, argv, thisVar);
314 NAPI_ASSERT(env, (argc == ARGS_ONE), "requires 1 parameters");
315 napi_get_undefined(env, &result);
316 int32_t sceneCode = GetIntFromParams(env, argv, PARAM0);
317 NAPI_INFO_LOG("GetBackupInfo, sceneCode = %{public}d", sceneCode);
318 if (sceneCode < 0) {
319 NAPI_INFO_LOG("Parameters error, sceneCode = %{public}d", sceneCode);
320 return result;
321 }
322 std::string backupInfo;
323 BackupRestoreService::GetInstance().GetBackupInfo(sceneCode, backupInfo);
324 CHECK_ARGS(env, napi_create_string_utf8(env, backupInfo.c_str(), NAPI_AUTO_LENGTH, &result), JS_INNER_FAIL);
325 return result;
326 }
327
JSGetProgressInfo(napi_env env,napi_callback_info info)328 napi_value MediaLibraryBackupNapi::JSGetProgressInfo(napi_env env, napi_callback_info info)
329 {
330 napi_value result = nullptr;
331 if (CheckPermission() != E_OK) {
332 return result;
333 }
334
335 std::string progressInfo;
336 BackupRestoreService::GetInstance().GetProgressInfo(progressInfo);
337 CHECK_ARGS(env, napi_create_string_utf8(env, progressInfo.c_str(), NAPI_AUTO_LENGTH, &result), JS_INNER_FAIL);
338 return result;
339 }
340
UvBackupWork(uv_loop_s * loop,uv_work_t * work)341 void MediaLibraryBackupNapi::UvBackupWork(uv_loop_s *loop, uv_work_t *work)
342 {
343 uv_queue_work(loop, work, [](uv_work_t *work) {
344 BackupBlock *block = reinterpret_cast<BackupBlock *> (work->data);
345 BackupRestoreService::GetInstance().StartBackup(block->sceneCode, block->galleryAppName,
346 block->mediaAppName);
347 }, [](uv_work_t *work, int _status) {
348 BackupBlock *block = reinterpret_cast<BackupBlock *> (work->data);
349 if (block == nullptr) {
350 delete work;
351 return;
352 }
353 napi_handle_scope scope = nullptr;
354 napi_open_handle_scope(block->env, &scope);
355 if (scope == nullptr) {
356 delete work;
357 return;
358 }
359 napi_value resultCode = nullptr;
360 napi_create_int32(block->env, 1, &resultCode);
361 napi_resolve_deferred(block->env, block->nativeDeferred, resultCode);
362 napi_close_handle_scope(block->env, scope);
363 delete block;
364 delete work;
365 });
366 }
367
JSStartBackup(napi_env env,napi_callback_info info)368 napi_value MediaLibraryBackupNapi::JSStartBackup(napi_env env, napi_callback_info info)
369 {
370 napi_value result = nullptr;
371 if (CheckPermission() != E_OK) {
372 return result;
373 }
374
375 size_t argc = ARGS_THREE;
376 napi_value argv[ARGS_THREE] = {0};
377 napi_value thisVar = nullptr;
378
379 GET_JS_ARGS(env, info, argc, argv, thisVar);
380 NAPI_ASSERT(env, (argc == ARGS_THREE), "requires 3 parameters");
381 napi_get_undefined(env, &result);
382 int32_t sceneCode = GetIntFromParams(env, argv, PARAM0);
383 std::string galleryAppName = GetStringFromParams(env, argv, PARAM1);
384 std::string mediaAppName = GetStringFromParams(env, argv, PARAM2);
385 NAPI_INFO_LOG("StartBackup, sceneCode = %{public}d", sceneCode);
386 if (sceneCode < 0) {
387 NAPI_INFO_LOG("Parameters error, sceneCode = %{public}d", sceneCode);
388 return result;
389 }
390 uv_loop_s *loop = nullptr;
391 napi_get_uv_event_loop(env, &loop);
392 uv_work_t *work = new (std::nothrow) uv_work_t;
393 if (work == nullptr) {
394 NAPI_ERR_LOG("Failed to new uv_work");
395 return result;
396 }
397 napi_deferred nativeDeferred = nullptr;
398 napi_create_promise(env, &nativeDeferred, &result);
399 BackupBlock *block = new (std::nothrow) BackupBlock {
400 env, sceneCode, galleryAppName, mediaAppName, nativeDeferred };
401 if (block == nullptr) {
402 NAPI_ERR_LOG("Failed to new block");
403 delete work;
404 return result;
405 }
406 work->data = reinterpret_cast<void *>(block);
407 UvBackupWork(loop, work);
408 return result;
409 }
410
JSStartBackupEx(napi_env env,napi_callback_info info)411 napi_value MediaLibraryBackupNapi::JSStartBackupEx(napi_env env, napi_callback_info info)
412 {
413 napi_value result = nullptr;
414 if (CheckPermission() != E_OK) {
415 return result;
416 }
417
418 size_t argc = ARGS_FOUR;
419 napi_value argv[ARGS_FOUR] = {0};
420 napi_value thisVar = nullptr;
421
422 GET_JS_ARGS(env, info, argc, argv, thisVar);
423 NAPI_ASSERT(env, (argc == ARGS_FOUR), "requires 4 parameters");
424 napi_get_undefined(env, &result);
425 int32_t sceneCode = GetIntFromParams(env, argv, PARAM0);
426 std::string galleryAppName = GetStringFromParams(env, argv, PARAM1);
427 std::string mediaAppName = GetStringFromParams(env, argv, PARAM2);
428 std::string backupInfo = GetStringFromParams(env, argv, PARAM3);
429 std::string backupExInfo;
430 NAPI_INFO_LOG("StartBackup, sceneCode = %{public}d", sceneCode);
431 if (sceneCode < 0) {
432 NAPI_INFO_LOG("Parameters error, sceneCode = %{public}d", sceneCode);
433 return result;
434 }
435 uv_loop_s *loop = nullptr;
436 napi_get_uv_event_loop(env, &loop);
437 uv_work_t *work = new (std::nothrow) uv_work_t;
438 if (work == nullptr) {
439 NAPI_ERR_LOG("Failed to new uv_work");
440 return result;
441 }
442 napi_deferred nativeDeferred = nullptr;
443 napi_create_promise(env, &nativeDeferred, &result);
444 BackupExBlock *block = new (std::nothrow) BackupExBlock {
445 env, sceneCode, galleryAppName, mediaAppName, nativeDeferred, backupInfo, backupExInfo };
446 if (block == nullptr) {
447 NAPI_ERR_LOG("Failed to new block");
448 delete work;
449 return result;
450 }
451 work->data = reinterpret_cast<void *>(block);
452 UvBackupWorkEx(loop, work);
453 return result;
454 }
455
UvBackupWorkEx(uv_loop_s * loop,uv_work_t * work)456 void MediaLibraryBackupNapi::UvBackupWorkEx(uv_loop_s *loop, uv_work_t *work)
457 {
458 uv_queue_work(loop, work, [](uv_work_t *work) {
459 BackupExBlock *block = reinterpret_cast<BackupExBlock *> (work->data);
460 BackupRestoreService::GetInstance().StartBackupEx(block->sceneCode, block->galleryAppName,
461 block->mediaAppName, block->backupInfo, block->backupExInfo);
462 }, [](uv_work_t *work, int _status) {
463 BackupExBlock *block = reinterpret_cast<BackupExBlock *> (work->data);
464 if (block == nullptr) {
465 delete work;
466 return;
467 }
468 napi_handle_scope scope = nullptr;
469 napi_open_handle_scope(block->env, &scope);
470 if (scope == nullptr) {
471 delete work;
472 return;
473 }
474 napi_value napiBackupExResult = nullptr;
475 napi_create_string_utf8(block->env, block->backupExInfo.c_str(), NAPI_AUTO_LENGTH, &napiBackupExResult);
476 napi_resolve_deferred(block->env, block->nativeDeferred, napiBackupExResult);
477 napi_close_handle_scope(block->env, scope);
478 delete block;
479 delete work;
480 });
481 }
482
JSRelease(napi_env env,napi_callback_info info)483 napi_value MediaLibraryBackupNapi::JSRelease(napi_env env, napi_callback_info info)
484 {
485 napi_value result = nullptr;
486 if (CheckPermission() != E_OK) {
487 return result;
488 }
489
490 size_t argc = ARGS_TWO;
491 napi_value argv[ARGS_TWO] = {0};
492 napi_value thisVar = nullptr;
493
494 GET_JS_ARGS(env, info, argc, argv, thisVar);
495 NAPI_ASSERT(env, (argc == ARGS_TWO), "requires 2 parameters");
496 napi_get_undefined(env, &result);
497 int32_t sceneCode = GetIntFromParams(env, argv, PARAM0);
498 int32_t releaseScene = GetIntFromParams(env, argv, PARAM1);
499 NAPI_INFO_LOG("Release, sceneCode:%{public}d releaseScene = %{public}d", sceneCode, releaseScene);
500 BackupRestoreService::GetInstance().Release(sceneCode, releaseScene);
501 return result;
502 }
503 } // namespace Media
504 } // namespace OHOS
505