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