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
Init(napi_env env,napi_value exports)54 napi_value MediaLibraryBackupNapi::Init(napi_env env, napi_value exports)
55 {
56 NAPI_INFO_LOG("Init, MediaLibraryBackupNapi has been used.");
57 napi_property_descriptor media_library_properties[] = {
58 DECLARE_NAPI_FUNCTION("startRestore", JSStartRestore),
59 DECLARE_NAPI_FUNCTION("startRestoreEx", JSStartRestoreEx),
60 DECLARE_NAPI_FUNCTION("getBackupInfo", JSGetBackupInfo),
61 DECLARE_NAPI_FUNCTION("getProgressInfo", JSGetProgressInfo),
62 DECLARE_NAPI_FUNCTION("startBackup", JSStartBackup),
63 };
64
65 NAPI_CALL(env, napi_define_properties(env, exports, sizeof(media_library_properties) /
66 sizeof(media_library_properties[0]), media_library_properties));
67 return exports;
68 }
69
GetIntFromParams(napi_env env,const napi_value args[],size_t index)70 static int32_t GetIntFromParams(napi_env env, const napi_value args[], size_t index)
71 {
72 int32_t result = -1;
73 napi_valuetype valueType = napi_undefined;
74 if (napi_typeof(env, args[index], &valueType) != napi_ok || valueType != napi_number) {
75 NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
76 return result;
77 }
78 napi_get_value_int32(env, args[index], &result);
79 return result;
80 }
81
GetStringFromParams(napi_env env,const napi_value args[],size_t index)82 static std::string GetStringFromParams(napi_env env, const napi_value args[], size_t index)
83 {
84 napi_valuetype valueType = napi_undefined;
85 if (napi_typeof(env, args[index], &valueType) != napi_ok || valueType != napi_string) {
86 NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
87 return "";
88 }
89
90 size_t resultLength;
91 napi_get_value_string_utf8(env, args[index], nullptr, 0, &resultLength);
92 std::string result(resultLength, '\0');
93 napi_get_value_string_utf8(env, args[index], &result[0], resultLength + 1, &resultLength);
94 return result;
95 }
96
CheckPermission(void)97 static int32_t CheckPermission(void)
98 {
99 auto context = AbilityRuntime::Context::GetApplicationContext();
100 if (context == nullptr) {
101 NAPI_ERR_LOG("Failed to get context");
102 return E_FAIL;
103 }
104 std::string bundleName = context->GetBundleName();
105 if (bundleName.compare(BUNDLE_NAME) != 0) {
106 NAPI_ERR_LOG("bundleName is invalid, %{public}s", bundleName.c_str());
107 return E_FAIL;
108 }
109 return E_OK;
110 }
111
UvQueueWork(uv_loop_s * loop,uv_work_t * work)112 void MediaLibraryBackupNapi::UvQueueWork(uv_loop_s *loop, uv_work_t *work)
113 {
114 uv_queue_work(loop, work, [](uv_work_t *work) {
115 RestoreBlock *block = reinterpret_cast<RestoreBlock *> (work->data);
116 if (block == nullptr) {
117 delete work;
118 return;
119 }
120 BackupRestoreService::GetInstance().StartRestore(block->context.lock(), block->restoreInfo);
121 }, [](uv_work_t *work, int _status) {
122 RestoreBlock *block = reinterpret_cast<RestoreBlock *> (work->data);
123 napi_handle_scope scope = nullptr;
124 napi_open_handle_scope(block->env, &scope);
125 if (scope == nullptr) {
126 delete work;
127 return;
128 }
129 napi_value resultCode = nullptr;
130 napi_create_int32(block->env, 1, &resultCode);
131 napi_resolve_deferred(block->env, block->nativeDeferred, resultCode);
132 napi_close_handle_scope(block->env, scope);
133 delete block;
134 delete work;
135 });
136 }
137
ParseContext(const napi_env & env,const napi_value & input,std::shared_ptr<OHOS::AbilityRuntime::Context> & context)138 bool ParseContext(const napi_env &env, const napi_value &input,
139 std::shared_ptr<OHOS::AbilityRuntime::Context> &context)
140 {
141 bool isStageMode = false;
142 napi_status status = OHOS::AbilityRuntime::IsStageContext(env, input, isStageMode);
143 if (status != napi_ok) {
144 NAPI_ERR_LOG("parse context status error, status:%{public}d", status);
145 return false;
146 }
147 if (!isStageMode) {
148 NAPI_ERR_LOG("parse context failed, not stage context");
149 return false;
150 }
151 context = OHOS::AbilityRuntime::GetStageModeContext(env, input);
152 if (context == nullptr) {
153 NAPI_ERR_LOG("parse context failed, context is null");
154 return false;
155 }
156
157 return true;
158 }
159
JSStartRestore(napi_env env,napi_callback_info info)160 napi_value MediaLibraryBackupNapi::JSStartRestore(napi_env env, napi_callback_info info)
161 {
162 napi_value result = nullptr;
163 if (CheckPermission() != E_OK) {
164 return result;
165 }
166
167 size_t argc = ARGS_FIVE;
168 napi_value argv[ARGS_FIVE] = {0};
169 napi_value thisVar = nullptr;
170
171 GET_JS_ARGS(env, info, argc, argv, thisVar);
172 NAPI_ASSERT(env, (argc == ARGS_FIVE), "requires 5 parameters");
173 napi_get_undefined(env, &result);
174
175 // get ability context
176 std::shared_ptr<OHOS::AbilityRuntime::Context> context;
177 if (!ParseContext(env, argv[PARAM0], context)) {
178 return result;
179 }
180 RestoreInfo restoreInfo;
181 restoreInfo.sceneCode = GetIntFromParams(env, argv, PARAM1);
182 restoreInfo.galleryAppName = GetStringFromParams(env, argv, PARAM2);
183 restoreInfo.mediaAppName = GetStringFromParams(env, argv, PARAM3);
184 restoreInfo.backupDir = GetStringFromParams(env, argv, PARAM4);
185 NAPI_INFO_LOG("StartRestore, sceneCode = %{public}d", restoreInfo.sceneCode);
186
187 if (restoreInfo.sceneCode < 0) {
188 NAPI_ERR_LOG("Parameters error, sceneCode = %{public}d", restoreInfo.sceneCode);
189 return result;
190 }
191 uv_loop_s *loop = nullptr;
192 napi_get_uv_event_loop(env, &loop);
193 uv_work_t *work = new (std::nothrow) uv_work_t;
194 if (work == nullptr) {
195 NAPI_ERR_LOG("Failed to new uv_work");
196 return result;
197 }
198 napi_deferred nativeDeferred = nullptr;
199 napi_create_promise(env, &nativeDeferred, &result);
200 RestoreBlock *block = new (std::nothrow) RestoreBlock { env, context, restoreInfo, nativeDeferred };
201 if (block == nullptr) {
202 NAPI_ERR_LOG("Failed to new block");
203 delete work;
204 return result;
205 }
206 work->data = reinterpret_cast<void *>(block);
207 UvQueueWork(loop, work);
208 return result;
209 }
210
UvQueueWorkEx(uv_loop_s * loop,uv_work_t * work)211 void MediaLibraryBackupNapi::UvQueueWorkEx(uv_loop_s *loop, uv_work_t *work)
212 {
213 uv_queue_work(loop, work, [](uv_work_t *work) {
214 RestoreExBlock *block = reinterpret_cast<RestoreExBlock *> (work->data);
215 BackupRestoreService::GetInstance().StartRestoreEx(block->context.lock(), block->restoreInfo,
216 block->restoreExInfo);
217 }, [](uv_work_t *work, int _status) {
218 RestoreExBlock *block = reinterpret_cast<RestoreExBlock *> (work->data);
219 if (block == nullptr) {
220 delete work;
221 return;
222 }
223 napi_handle_scope scope = nullptr;
224 napi_open_handle_scope(block->env, &scope);
225 if (scope == nullptr) {
226 delete work;
227 return;
228 }
229 napi_value restoreExResult = nullptr;
230 napi_create_string_utf8(block->env, block->restoreExInfo.c_str(), NAPI_AUTO_LENGTH, &restoreExResult);
231 napi_resolve_deferred(block->env, block->nativeDeferred, restoreExResult);
232 napi_close_handle_scope(block->env, scope);
233 delete block;
234 delete work;
235 });
236 }
237
JSStartRestoreEx(napi_env env,napi_callback_info info)238 napi_value MediaLibraryBackupNapi::JSStartRestoreEx(napi_env env, napi_callback_info info)
239 {
240 napi_value result = nullptr;
241 if (CheckPermission() != E_OK) {
242 return result;
243 }
244
245 size_t argc = ARGS_SIX;
246 napi_value argv[ARGS_SIX] = {0};
247 napi_value thisVar = nullptr;
248
249 GET_JS_ARGS(env, info, argc, argv, thisVar);
250 NAPI_ASSERT(env, (argc == ARGS_SIX), "requires 6 parameters");
251 napi_get_undefined(env, &result);
252 // get ability context
253 std::shared_ptr<OHOS::AbilityRuntime::Context> context;
254 if (!ParseContext(env, argv[PARAM0], context)) {
255 return result;
256 }
257 RestoreInfo restoreInfo;
258 restoreInfo.sceneCode = GetIntFromParams(env, argv, PARAM1);
259 restoreInfo.galleryAppName = GetStringFromParams(env, argv, PARAM2);
260 restoreInfo.mediaAppName = GetStringFromParams(env, argv, PARAM3);
261 restoreInfo.backupDir = GetStringFromParams(env, argv, PARAM4);
262 restoreInfo.bundleInfo = GetStringFromParams(env, argv, PARAM5);
263 std::string restoreExInfo;
264 NAPI_INFO_LOG("StartRestoreEx, sceneCode = %{public}d", restoreInfo.sceneCode);
265 if (restoreInfo.sceneCode < 0) {
266 NAPI_INFO_LOG("Parameters error, sceneCode = %{public}d", restoreInfo.sceneCode);
267 return result;
268 }
269 uv_loop_s *loop = nullptr;
270 napi_get_uv_event_loop(env, &loop);
271 uv_work_t *work = new (std::nothrow) uv_work_t;
272 if (work == nullptr) {
273 NAPI_ERR_LOG("Failed to new uv_work");
274 return result;
275 }
276 napi_deferred nativeDeferred = nullptr;
277 napi_create_promise(env, &nativeDeferred, &result);
278 RestoreExBlock *block = new (std::nothrow) RestoreExBlock {
279 env, context, restoreInfo, restoreExInfo, nativeDeferred };
280 if (block == nullptr) {
281 NAPI_ERR_LOG("Failed to new block");
282 delete work;
283 return result;
284 }
285 work->data = reinterpret_cast<void *>(block);
286 UvQueueWorkEx(loop, work);
287 return result;
288 }
289
JSGetBackupInfo(napi_env env,napi_callback_info info)290 napi_value MediaLibraryBackupNapi::JSGetBackupInfo(napi_env env, napi_callback_info info)
291 {
292 napi_value result = nullptr;
293 if (CheckPermission() != E_OK) {
294 return result;
295 }
296
297 size_t argc = ARGS_ONE;
298 napi_value argv[ARGS_ONE] = {0};
299 napi_value thisVar = nullptr;
300
301 GET_JS_ARGS(env, info, argc, argv, thisVar);
302 NAPI_ASSERT(env, (argc == ARGS_ONE), "requires 1 parameters");
303 napi_get_undefined(env, &result);
304 int32_t sceneCode = GetIntFromParams(env, argv, PARAM0);
305 NAPI_INFO_LOG("GetBackupInfo, sceneCode = %{public}d", sceneCode);
306 if (sceneCode < 0) {
307 NAPI_INFO_LOG("Parameters error, sceneCode = %{public}d", sceneCode);
308 return result;
309 }
310 std::string backupInfo;
311 BackupRestoreService::GetInstance().GetBackupInfo(sceneCode, backupInfo);
312 CHECK_ARGS(env, napi_create_string_utf8(env, backupInfo.c_str(), NAPI_AUTO_LENGTH, &result), JS_INNER_FAIL);
313 return result;
314 }
315
JSGetProgressInfo(napi_env env,napi_callback_info info)316 napi_value MediaLibraryBackupNapi::JSGetProgressInfo(napi_env env, napi_callback_info info)
317 {
318 napi_value result = nullptr;
319 if (CheckPermission() != E_OK) {
320 return result;
321 }
322
323 std::string progressInfo;
324 BackupRestoreService::GetInstance().GetProgressInfo(progressInfo);
325 CHECK_ARGS(env, napi_create_string_utf8(env, progressInfo.c_str(), NAPI_AUTO_LENGTH, &result), JS_INNER_FAIL);
326 return result;
327 }
328
UvBackupWork(uv_loop_s * loop,uv_work_t * work)329 void MediaLibraryBackupNapi::UvBackupWork(uv_loop_s *loop, uv_work_t *work)
330 {
331 uv_queue_work(loop, work, [](uv_work_t *work) {
332 BackupBlock *block = reinterpret_cast<BackupBlock *> (work->data);
333 BackupRestoreService::GetInstance().StartBackup(block->sceneCode, block->galleryAppName,
334 block->mediaAppName);
335 }, [](uv_work_t *work, int _status) {
336 BackupBlock *block = reinterpret_cast<BackupBlock *> (work->data);
337 if (block == nullptr) {
338 delete work;
339 return;
340 }
341 napi_handle_scope scope = nullptr;
342 napi_open_handle_scope(block->env, &scope);
343 if (scope == nullptr) {
344 delete work;
345 return;
346 }
347 napi_value resultCode = nullptr;
348 napi_create_int32(block->env, 1, &resultCode);
349 napi_resolve_deferred(block->env, block->nativeDeferred, resultCode);
350 napi_close_handle_scope(block->env, scope);
351 delete block;
352 delete work;
353 });
354 }
355
JSStartBackup(napi_env env,napi_callback_info info)356 napi_value MediaLibraryBackupNapi::JSStartBackup(napi_env env, napi_callback_info info)
357 {
358 napi_value result = nullptr;
359 if (CheckPermission() != E_OK) {
360 return result;
361 }
362
363 size_t argc = ARGS_THREE;
364 napi_value argv[ARGS_THREE] = {0};
365 napi_value thisVar = nullptr;
366
367 GET_JS_ARGS(env, info, argc, argv, thisVar);
368 NAPI_ASSERT(env, (argc == ARGS_THREE), "requires 3 parameters");
369 napi_get_undefined(env, &result);
370 int32_t sceneCode = GetIntFromParams(env, argv, PARAM0);
371 std::string galleryAppName = GetStringFromParams(env, argv, PARAM1);
372 std::string mediaAppName = GetStringFromParams(env, argv, PARAM2);
373 NAPI_INFO_LOG("StartBackup, sceneCode = %{public}d", sceneCode);
374 if (sceneCode < 0) {
375 NAPI_INFO_LOG("Parameters error, sceneCode = %{public}d", sceneCode);
376 return result;
377 }
378 uv_loop_s *loop = nullptr;
379 napi_get_uv_event_loop(env, &loop);
380 uv_work_t *work = new (std::nothrow) uv_work_t;
381 if (work == nullptr) {
382 NAPI_ERR_LOG("Failed to new uv_work");
383 return result;
384 }
385 napi_deferred nativeDeferred = nullptr;
386 napi_create_promise(env, &nativeDeferred, &result);
387 BackupBlock *block = new (std::nothrow) BackupBlock {
388 env, sceneCode, galleryAppName, mediaAppName, nativeDeferred };
389 if (block == nullptr) {
390 NAPI_ERR_LOG("Failed to new block");
391 delete work;
392 return result;
393 }
394 work->data = reinterpret_cast<void *>(block);
395 UvBackupWork(loop, work);
396 return result;
397 }
398 } // namespace Media
399 } // namespace OHOS
400