diff --git a/bundle.json b/bundle.json index 57f026e1d6aa4f65ea6fe37c44bd4e991724741e..e495f6606dd4d1f777da45fac24ee098f8ec3f80 100644 --- a/bundle.json +++ b/bundle.json @@ -71,6 +71,8 @@ "//foundation/filemanagement/app_file_service/interfaces/kits/js:fileshare", "//foundation/filemanagement/app_file_service/interfaces/kits/js:fileuri", "//foundation/filemanagement/app_file_service/interfaces/kits/js:backup", + "//foundation/filemanagement/app_file_service/interfaces/kits/js:backup_inner", + "//foundation/filemanagement/app_file_service/interfaces/kits/ani/backup:backup_ani_package", "//foundation/filemanagement/app_file_service/interfaces/kits/ani/file_uri:fileuri_ani_package", "//foundation/filemanagement/app_file_service/interfaces/kits/ndk/fileuri/src:ohfileuri", "//foundation/filemanagement/app_file_service/interfaces/kits/ndk/fileshare/src:ohfileshare", diff --git a/interfaces/kits/ani/backup/BUILD.gn b/interfaces/kits/ani/backup/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..6193628f43d7131604c5e5fc84224cc4f2d5672d --- /dev/null +++ b/interfaces/kits/ani/backup/BUILD.gn @@ -0,0 +1,101 @@ +# Copyright (c) 2025 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build/config/components/ets_frontend/ets2abc_config.gni") +import("//build/ohos.gni") +import("//foundation/filemanagement/app_file_service/app_file_service.gni") + +ohos_shared_library("ani_session_transfer") { + visibility = [ ":*" ] + branch_protector_ret = "pac_ret" + sanitize = { + boundary_sanitize = true + ubsan = true + cfi = true + cfi_cross_dso = true + debug = false + } + + defines = [ + "LOG_DOMAIN=0xD004306", + "LOG_TAG=\"BackupANI\"", + ] + + cflags_cc = [ "-Wno-unused-function" ] + sources = [ + "../../../common/src/common_func.cpp", + "../../../common/src/sandbox_helper.cpp", + "../../../common/src/json_utils.cpp", + "src/incr_backup_session_transfer.cpp", + "src/incremental_backup_session.cpp", + "src/ani_constructor.cpp", + "../utils/src/ani_utils.cpp" + ] + + include_dirs = [ + "include", + "../utils/include", + "../../../common/include", + "../../js/backup", + "${app_file_service_path}/interfaces/inner_api/native/backup_kit_inner/impl", + ] + + deps = [ + "${app_file_service_path}/interfaces/inner_api/native/backup_kit_inner:backup_kit_inner", + "${app_file_service_path}/interfaces/kits/js:backup_inner", + "${app_file_service_path}/utils:backup_utils" + ] + + external_deps = [ + "ability_base:zuri", + "bundle_framework:appexecfwk_base", + "bundle_framework:appexecfwk_core", + "c_utils:utils", + "file_api:filemgmt_libhilog", + "file_api:filemgmt_libn", + "hilog:libhilog", + "ipc:ipc_core", + "napi:ace_napi", + "runtime_core:ani", + "runtime_core:ani_helpers", + "samgr:samgr_proxy", + ] + use_exceptions = true + part_name = "app_file_service" + subsystem_name = "filemanagement" + output_extension = "so" +} + +generate_static_abc("backup_transfer_abc") { + base_url = "./ets" + files = [ "./ets/@ohos.backup.transfer.ets" ] + dst_file = "$target_out_dir/backup_transfer.abc" + out_puts = [ "$target_out_dir/backup_transfer.abc" ] + is_boot_abc = "True" + device_dst_file = "/system/framework/backup_transfer.abc" +} + +ohos_prebuilt_etc("backup_transfer_abc_etc") { + source = "$target_out_dir/backup_transfer.abc" + module_install_dir = "framework" + subsystem_name = "filemanagement" + part_name = "app_file_service" + deps = [ ":backup_transfer_abc" ] +} + +group("backup_ani_package") { + deps = [ + ":backup_transfer_abc_etc", + ":ani_session_transfer", + ] +} diff --git a/interfaces/kits/ani/backup/ets/@ohos.backup.transfer.ets b/interfaces/kits/ani/backup/ets/@ohos.backup.transfer.ets new file mode 100644 index 0000000000000000000000000000000000000000..59613abae9ffcc76baa0c19217025f7c823fcb0c --- /dev/null +++ b/interfaces/kits/ani/backup/ets/@ohos.backup.transfer.ets @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export namespace backup { + interface Cleaner { + clean(): void + } + class IncrBackupSessionCleaner implements Cleaner { + static { + loadLibrary("ani_session_transfer"); + } + private session: long = 0 + private callbacks: long = 0 + constructor(session: long, callbacks: long) { + this.session = session; + this.callbacks = callbacks; + } + native clean(): void + } + + export function callback(cleaner: Cleaner): void { + cleaner.clean(); + } + let destroyRegister = new FinalizationRegistry(callback); + let unregisterToken = new object() + + class BIncrementalData { + public bundleName: string = ''; + public lastIncrementalTime: long = 0; + public manifestFd: int = 0; + public backupParameters: string = ''; + public backupPriority: int = 0; + } + + class IncrementalBackupSession { + static { + loadLibrary("ani_session_transfer"); + } + + public native getLocalCapabilities(): int; + public native getBackupDataSize(isPreciseScan: boolean, bundleNames: Array): int; + public native appendBundles(bundleInfos: Array): int; + public native release(): int; + public native cancel(bundleName: string): int; + public native cleanBundleTempDir(bundleName: string): int; + + public session: long = 0; + public callbacks: long = 0; + private cleaner: IncrBackupSessionCleaner | null = null; + constructor(session: long, callbacks: long) { + this.session = session; + this.callbacks = callbacks; + this.registerCleaner(); + } + + registerCleaner(): void { + this.cleaner = new IncrBackupSessionCleaner(this.session, this.callbacks); + destroyRegister.register(this, this.cleaner!, unregisterToken); + } + } + + class IncrBackupSessionTransfer { + static { + loadLibrary("ani_session_transfer"); + } + + private static native transferStaticSession(input: ESValue): Object; + private static native transferDynamicSession(input: Object): ESValue; + static transferStatic(input: Any): Object { // 1.1(dynamic) => 1.2(static) + return IncrBackupSessionTransfer.transferStaticSession(ESValue.wrap(input)); + } + static transferDynamic(input: Object): Any { // 1.2 => 1.1 + return IncrBackupSessionTransfer.transferDynamicSession(input); + } + } +} \ No newline at end of file diff --git a/interfaces/kits/ani/backup/include/incr_backup_session_transfer.h b/interfaces/kits/ani/backup/include/incr_backup_session_transfer.h new file mode 100644 index 0000000000000000000000000000000000000000..441241278d59cc0d3fb7f13a6b0f5d80f30a4a68 --- /dev/null +++ b/interfaces/kits/ani/backup/include/incr_backup_session_transfer.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef INCR_BACKUP_SESSION_TRANSFER_H +#define INCR_BACKUP_SESSION_TRANSFER_H + +#include +#include +#include "native_engine/native_engine.h" + +namespace OHOS::FileManagement::Backup { +class IncreBackupSessionTransfer { +public: + IncreBackupSessionTransfer() = default; + ~IncreBackupSessionTransfer() = default; + + IncreBackupSessionTransfer(const IncreBackupSessionTransfer&) = delete; + IncreBackupSessionTransfer(IncreBackupSessionTransfer&&) = delete; + IncreBackupSessionTransfer& operator=(const IncreBackupSessionTransfer&) = delete; + IncreBackupSessionTransfer& operator=(IncreBackupSessionTransfer&&) = delete; + + static void Init(ani_env *aniEnv); + static ani_object TransferStaticSession(ani_env *aniEnv, ani_class aniCls, ani_object input); + static ani_ref TransferDynamicSession(ani_env *aniEnv, ani_class aniCls, ani_object input); +}; +} // namespace OHOS::FileManagement::Backup +#endif // INCR_BACKUP_SESSION_TRANSFER_H \ No newline at end of file diff --git a/interfaces/kits/ani/backup/include/incremental_backup_session.h b/interfaces/kits/ani/backup/include/incremental_backup_session.h new file mode 100644 index 0000000000000000000000000000000000000000..81ef102a12a1646c47f7f4f407298629cab6560e --- /dev/null +++ b/interfaces/kits/ani/backup/include/incremental_backup_session.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef INCREMENTAL_BACKUP_SESSION__H +#define INCREMENTAL_BACKUP_SESSION__H + +#include +#include +#include +#include "b_incremental_backup_session.h" +#include "general_callbacks.h" +#include "native_engine/native_engine.h" +#include "session_incremental_backup_n_exporter.h" + +namespace OHOS::FileManagement::Backup { +class IncrementalBackupSession { +public: + ~IncrementalBackupSession() = default; + + IncrementalBackupSession(const IncrementalBackupSession&) = delete; + IncrementalBackupSession(IncrementalBackupSession&&) = delete; + IncrementalBackupSession& operator=(const IncrementalBackupSession&) = delete; + IncrementalBackupSession& operator=(IncrementalBackupSession&&) = delete; + + static void Init(ani_env *aniEnv); + static int32_t checkPermission(ani_env *aniEnv); + static ani_int GetLocalCapabilities(ani_env *aniEnv, ani_object object); + static ani_int GetBackupDataSize(ani_env *aniEnv, ani_object object, ani_boolean isPreciseScan, + ani_array bundleNames); + static ani_int AppendBundles(ani_env *aniEnv, ani_object object, ani_array bundleInfos); + static ani_int Release(ani_env *aniEnv, ani_object object); + static ani_int Cancel(ani_env *aniEnv, ani_object object, ani_string bundleName); + static ani_int CleanBundleTempDir(ani_env *aniEnv, ani_object object, ani_string bundleName); + + static bool ParseIncrDataFromAniArray(ani_env *aniEnv, ani_array bundleInfos, + std::vector& result); + static bool ParseBIncrementalData(ani_env *aniEnv, ani_object obj, BIncrementalData& data); + + std::unique_ptr session; + std::shared_ptr callbacks; +}; + +class IncrBackupSessionCleaner { +public: + static void Clean(ani_env *aniEnv, ani_object object); +}; +} // namespace OHOS::FileManagement::Backup +#endif // INCREMENTAL_BACKUP_SESSION__H \ No newline at end of file diff --git a/interfaces/kits/ani/backup/src/ani_constructor.cpp b/interfaces/kits/ani/backup/src/ani_constructor.cpp new file mode 100644 index 0000000000000000000000000000000000000000..bda7c89578a86a456157afbf83af3a591f6db9ae --- /dev/null +++ b/interfaces/kits/ani/backup/src/ani_constructor.cpp @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include "incr_backup_session_transfer.h" +#include "incremental_backup_session.h" + +namespace OHOS::FileManagement::Backup { +extern "C" { + ANI_EXPORT ani_status ANI_Constructor(ani_vm *vm, uint32_t *result) + { + ani_env *env; + if (ANI_OK != vm->GetEnv(ANI_VERSION_1, &env)) { + return ANI_ERROR; + } + IncreBackupSessionTransfer::Init(env); + IncrementalBackupSession::Init(env); + *result = ANI_VERSION_1; + return ANI_OK; + } +} +} \ No newline at end of file diff --git a/interfaces/kits/ani/backup/src/incr_backup_session_transfer.cpp b/interfaces/kits/ani/backup/src/incr_backup_session_transfer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4aebe1ac7cd2070c965af2b65ad6aa81332ed523 --- /dev/null +++ b/interfaces/kits/ani/backup/src/incr_backup_session_transfer.cpp @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "incr_backup_session_transfer.h" + +#include +#include +#include +#include +#include +#include "interop_js/arkts_interop_js_api.h" +#include "interop_js/arkts_esvalue.h" +#include "filemgmt_libhilog.h" +#include "incremental_backup_session.h" +#include "napi/native_api.h" +#include "napi/native_node_api.h" +#include "native_engine/native_engine.h" +#include "session_incremental_backup_n_exporter.h" + +namespace OHOS::FileManagement::Backup { +namespace { +const char *INCR_BACKUP_SESSION_TRANSFER_CLASS_NAME = "L@ohos/backup/transfer/backup/IncrBackupSessionTransfer;"; +const char *INCR_BACKUP_SESSION_CLASS_NAME = "L@ohos/backup/transfer/backup/IncrementalBackupSession;"; +} + +void IncreBackupSessionTransfer::Init(ani_env *aniEnv) +{ + HILOGD("Init transfer native method begin"); + if (aniEnv == nullptr) { + HILOGE("aniEnv is null"); + return; + } + + ani_class cls = nullptr; + auto status = aniEnv->FindClass(INCR_BACKUP_SESSION_TRANSFER_CLASS_NAME, &cls); + if (status != ANI_OK) { + HILOGE("FindClass failed status: %{public}d", status); + return; + } + + std::array nativeFuncs = { + ani_native_function { "transferStaticSession", nullptr, + reinterpret_cast(IncreBackupSessionTransfer::TransferStaticSession)}, + ani_native_function { "transferDynamicSession", nullptr, + reinterpret_cast(IncreBackupSessionTransfer::TransferDynamicSession)}, + }; + status = aniEnv->Class_BindStaticNativeMethods(cls, nativeFuncs.data(), nativeFuncs.size()); + if (status != ANI_OK) { + HILOGE("Class_BindNativeMethods failed status: %{public}d", status); + return; + } + HILOGD("Init transfer native method end"); +} + +ani_object IncreBackupSessionTransfer::TransferStaticSession(ani_env *aniEnv, ani_class aniCls, ani_object input) +{ + HILOGD("Transfer incrBackupSession Static begin"); + if (aniEnv == nullptr) { + HILOGE("aniEnv is null"); + return nullptr; + } + + void *unwrapResult = nullptr; + bool unwrapRet = arkts_esvalue_unwrap(aniEnv, input, &unwrapResult); + if (!unwrapRet) { + HILOGE("Failed to unwrap"); + return nullptr; + } + if (unwrapResult == nullptr) { + HILOGE("UnwrapResult is nullptr"); + return nullptr; + } + // 1.1->1.2 + IncrementalBackupSession* entity = reinterpret_cast(unwrapResult); + ani_class cls = nullptr; + ani_status ret = ANI_ERROR; + if ((ret = aniEnv->FindClass(INCR_BACKUP_SESSION_CLASS_NAME, &cls)) != ANI_OK) { + HILOGE("Call FindClass failed, ret = %{public}d", ret); + return nullptr; + } + ani_method constructFunc; + if ((ret = aniEnv->Class_FindMethod(cls, "", nullptr, &constructFunc)) != ANI_OK) { + HILOGE("Call Class_FindMethod failed, ret = %{public}d", ret); + return nullptr; + } + ani_object outObj; + ret = aniEnv->Object_New(cls, constructFunc, &outObj, entity->session.release(), entity->callbacks.get()); + if (ret != ANI_OK) { + HILOGE("Call Object_New failed, ret = %{public}d", ret); + return nullptr; + } + HILOGD("Transfer incrBackupSession Static end"); + return outObj; +} + +ani_ref IncreBackupSessionTransfer::TransferDynamicSession(ani_env *aniEnv, ani_class aniCls, ani_object input) +{ + HILOGD("TransferDynamicSession start"); + if (aniEnv == nullptr) { + HILOGE("aniEnv is null"); + return nullptr; + } + // 1.2->1.1 + ani_status ret = ANI_ERROR; + ani_long session {}; + if ((ret = aniEnv->Object_GetPropertyByName_Long(input, "session", &session)) != ANI_OK) { + HILOGE("get field session failed, ret:%{public}d", ret); + return nullptr; + } + ani_long callbacks {}; + if ((ret = aniEnv->Object_GetPropertyByName_Long(input, "callbacks", &callbacks)) != ANI_OK) { + HILOGE("get field callbacks failed, ret:%{public}d", ret); + return nullptr; + } + IncrBackupEntity* entity = new IncrBackupEntity(); + std::unique_ptr sessionPtr(reinterpret_cast(session)); + entity->session = move(sessionPtr); + std::shared_ptr callbackPtr(reinterpret_cast(callbacks)); + entity->callbacks = callbackPtr; + napi_env jsEnv; + if (!arkts_napi_scope_open(aniEnv, &jsEnv)) { + HILOGE("Failed to arkts_napi_scope_open"); + delete entity; + return nullptr; + } + napi_value napiEntity = SessionIncrementalBackupNExporter::CreateByEntity(jsEnv, entity); + if (napiEntity == nullptr) { + HILOGD("Failed to create napi obj"); + delete entity; + return nullptr; + } + ani_ref outObj; + if (!arkts_napi_scope_close_n(jsEnv, 1, &napiEntity, &outObj)) { + HILOGE("Failed to arkts_napi_scope_close_n"); + delete entity; + return nullptr; + } + HILOGD("TransferDynamicSession end"); + delete entity; + return outObj; +} +} diff --git a/interfaces/kits/ani/backup/src/incremental_backup_session.cpp b/interfaces/kits/ani/backup/src/incremental_backup_session.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0041b7b799a610a2fe3e25512aabd68181c5c96b --- /dev/null +++ b/interfaces/kits/ani/backup/src/incremental_backup_session.cpp @@ -0,0 +1,322 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "incremental_backup_session.h" +#include +#include +#include +#include +#include "ani_utils.h" +#include "b_sa/b_sa_utils.h" +#include "filemgmt_libhilog.h" +#include "napi/native_api.h" +#include "napi/native_node_api.h" +#include "native_engine/native_engine.h" + +namespace OHOS::FileManagement::Backup { +using namespace LibN; + +namespace { +const char *INCR_BACKUP_SESSION_CLASS_NAME = "L@ohos/backup/transfer/backup/IncrementalBackupSession;"; +const char *B_INCREMENTAL_DATA_CLASS_NAME = "L@ohos/backup/transfer/backup/BIncrementalData;"; +const char *INCR_BACKUP_SESSION_CLEANER_CLASS_NAME = "L@ohos/backup/transfer/backup/IncrBackupSessionCleaner;"; +constexpr int32_t E_OK = 0; +} + +void IncrementalBackupSession::Init(ani_env *aniEnv) +{ + HILOGD("Init IncrementalBackupSession begin"); + if (aniEnv == nullptr) { + HILOGE("aniEnv is null"); + return; + } + + ani_class clsCleaner = AniUtils::GetAniClsByName(aniEnv, INCR_BACKUP_SESSION_CLEANER_CLASS_NAME); + if (clsCleaner == nullptr) { + return; + } + std::array cleanNativeFuncs = { + ani_native_function {"clean", ":V", reinterpret_cast(IncrBackupSessionCleaner::Clean)}, + }; + auto status = aniEnv->Class_BindNativeMethods(clsCleaner, cleanNativeFuncs.data(), cleanNativeFuncs.size()); + if (status != ANI_OK) { + HILOGE("Class_BindNativeMethods failed status: %{public}d", status); + return; + } + + ani_class cls = AniUtils::GetAniClsByName(aniEnv, INCR_BACKUP_SESSION_CLASS_NAME); + if (cls == nullptr) { + return; + } + + std::array nativeFuncs = { + ani_native_function {"getLocalCapabilities", ":i", + reinterpret_cast(IncrementalBackupSession::GetLocalCapabilities)}, + ani_native_function {"getBackupDataSize", "zC{escompat.Array}:i", + reinterpret_cast(IncrementalBackupSession::GetBackupDataSize)}, + ani_native_function {"appendBundles", "C{escompat.Array}:i", + reinterpret_cast(IncrementalBackupSession::AppendBundles)}, + ani_native_function {"release", ":i", + reinterpret_cast(IncrementalBackupSession::Release)}, + ani_native_function {"cancel", "C{std.core.String}:i", + reinterpret_cast(IncrementalBackupSession::Cancel)}, + ani_native_function {"cleanBundleTempDir", "C{std.core.String}:i", + reinterpret_cast(IncrementalBackupSession::CleanBundleTempDir)}, + }; + status = aniEnv->Class_BindNativeMethods(cls, nativeFuncs.data(), nativeFuncs.size()); + if (status != ANI_OK) { + HILOGE("Class_BindNativeMethods failed status: %{public}d", status); + return; + } + HILOGD("Init IncrementalBackupSession end"); +} + +bool IncrementalBackupSession::ParseBIncrementalData(ani_env* env, ani_object dataObj, BIncrementalData& data) +{ + if (env == nullptr) { + HILOGE("aniEnv is null"); + return false; + } + ani_ref aniBundleName {}; + int32_t status = 0; + status = env->Object_GetFieldByName_Ref(dataObj, "bundleName", &aniBundleName); + if (status != ANI_OK) { + HILOGE("get field bundleName fail, ret=%{public}d", status); + return false; + } + if (!AniUtils::AniObjectToStdString(env, static_cast(aniBundleName), data.bundleName)) { + HILOGE("parse bundleName fail"); + return false; + } + ani_long lastIncrementalTime = 0; + status = env->Object_GetFieldByName_Long(dataObj, "lastIncrementalTime", &lastIncrementalTime); + if (status != ANI_OK) { + HILOGE("get field lastIncrementalTime fail, ret=%{public}d", status); + return false; + } + ani_int manifestFd = 0; + status = env->Object_GetFieldByName_Int(dataObj, "manifestFd", &manifestFd); + if (status != ANI_OK) { + HILOGE("get field manifestFd fail, ret=%{public}d", status); + return false; + } + ani_ref aniBackupParameters {}; + status = env->Object_GetFieldByName_Ref(dataObj, "backupParameters", &aniBackupParameters); + if (status != ANI_OK) { + HILOGE("get field backupParameters fail, ret=%{public}d", status); + return false; + } + if (!AniUtils::AniObjectToStdString(env, static_cast(aniBackupParameters), data.backupParameters)) { + HILOGE("parse backupParameters fail"); + return false; + } + ani_int backupPriority = 0; + status = env->Object_GetFieldByName_Int(dataObj, "backupPriority", &backupPriority); + if (status != ANI_OK) { + HILOGE("get field backupPriority fail, ret=%{public}d", status); + return false; + } + data.lastIncrementalTime = lastIncrementalTime; + data.manifestFd = manifestFd; + data.backupPriority = backupPriority; + return true; +} + +bool IncrementalBackupSession::ParseIncrDataFromAniArray(ani_env *aniEnv, ani_array bundles, + std::vector& result) +{ + if (aniEnv == nullptr) { + HILOGE("aniEnv is null"); + return false; + } + ani_size arrSize = 0; + if (ANI_OK != aniEnv->Array_GetLength(bundles, &arrSize)) { + HILOGE("Array_GetLength fail"); + return false; + } + if (arrSize == 0) { + return false; + } + for (ani_size idx = 0; idx < arrSize; idx++) { + ani_ref item; + if (ANI_OK != aniEnv->Array_Get(bundles, idx, &item)) { + HILOGE("Array_Get fail, idx=%{public}zu", idx); + return false; + } + ani_class incrementalDataCls = AniUtils::GetAniClsByName(aniEnv, B_INCREMENTAL_DATA_CLASS_NAME); + if (incrementalDataCls == nullptr) { + return false; + } + ani_boolean isIncrementalData = ANI_FALSE; + ani_object dataObj = static_cast(item); + aniEnv->Object_InstanceOf(dataObj, incrementalDataCls, &isIncrementalData); + if (!isIncrementalData) { + HILOGE("arr element is not BIncrementalData"); + return false; + } + BIncrementalData incrData; + if (!ParseBIncrementalData(aniEnv, dataObj, incrData)) { + HILOGE("BIncrementalData fail"); + return false; + } + result.push_back(incrData); + } + return true; +} + +int32_t IncrementalBackupSession::checkPermission(ani_env *aniEnv) +{ + if (aniEnv == nullptr) { + HILOGE("aniEnv is null"); + return -E_PARAMS; + } + if (!SAUtils::CheckBackupPermission()) { + HILOGE("Has not permission!"); + return -E_PERMISSION; + } + if (!SAUtils::IsSystemApp()) { + HILOGE("System App check fail!"); + return -E_PERMISSION_SYS; + } + return E_OK; +} + +ani_int IncrementalBackupSession::GetLocalCapabilities(ani_env *aniEnv, ani_object object) +{ + int32_t checkRet; + if ((checkRet = checkPermission(aniEnv)) != E_OK) { + return checkRet; + } + IncrementalBackupSession* entity = reinterpret_cast(object); + if (entity == nullptr || entity->session == nullptr) { + HILOGE("object is invalid"); + return -E_PARAMS; + } + UniqueFd fd = entity->session->GetLocalCapabilities(); + return fd.Release(); +} + +ani_int IncrementalBackupSession::GetBackupDataSize(ani_env *aniEnv, ani_object object, ani_boolean isPreciseScan, + ani_array bundles) +{ + int32_t checkRet; + if ((checkRet = checkPermission(aniEnv)) != E_OK) { + return checkRet; + } + std::vector bundleInfos; + bool parseRet = ParseIncrDataFromAniArray(aniEnv, bundles, bundleInfos); + if (!parseRet || bundleInfos.size() == 0) { + HILOGE("parse fail or bundles is empty"); + return -E_PARAMS; + } + IncrementalBackupSession* entity = reinterpret_cast(object); + if (entity == nullptr || entity->session == nullptr) { + HILOGE("object is invalid"); + return -E_PARAMS; + } + return entity->session->GetBackupDataSize(isPreciseScan, bundleInfos); +} + +ani_int IncrementalBackupSession::AppendBundles(ani_env *aniEnv, ani_object object, ani_array bundles) +{ + int32_t checkRet; + if ((checkRet = checkPermission(aniEnv)) != E_OK) { + return checkRet; + } + IncrementalBackupSession* entity = reinterpret_cast(object); + if (entity == nullptr || entity->session == nullptr) { + HILOGE("object is invalid"); + return -E_PARAMS; + } + std::vector bundleInfos; + bool parseResult = ParseIncrDataFromAniArray(aniEnv, bundles, bundleInfos); + if (!parseResult || bundleInfos.size() == 0) { + HILOGE("parse fail or bundles is empty"); + return -E_PARAMS; + } + std::vector bundleNames; + for (const BIncrementalData& item: bundleInfos) { + bundleNames.push_back(item.bundleName); + } + return entity->session->AppendBundles(bundleInfos, bundleNames); +} + +ani_int IncrementalBackupSession::Release(ani_env *aniEnv, ani_object object) +{ + int32_t checkRet; + if ((checkRet = checkPermission(aniEnv)) != E_OK) { + return checkRet; + } + IncrementalBackupSession* entity = reinterpret_cast(object); + if (entity == nullptr || entity->session == nullptr) { + HILOGE("object is invalid"); + return -E_PARAMS; + } + return entity->session->Release(); +} + +ani_int IncrementalBackupSession::Cancel(ani_env *aniEnv, ani_object object, ani_string bundleName) +{ + int32_t checkRet; + if ((checkRet = checkPermission(aniEnv)) != E_OK) { + return checkRet; + } + IncrementalBackupSession* entity = reinterpret_cast(object); + if (entity == nullptr || entity->session == nullptr) { + HILOGE("object is invalid"); + return -E_PARAMS; + } + std::string bundle = AniUtils::AniStringToStdString(aniEnv, bundleName); + return entity->session->Cancel(bundle); +} + +ani_int IncrementalBackupSession::CleanBundleTempDir(ani_env *aniEnv, ani_object object, ani_string bundleName) +{ + int32_t checkRet; + if ((checkRet = checkPermission(aniEnv)) != E_OK) { + return checkRet; + } + IncrementalBackupSession* entity = reinterpret_cast(object); + if (entity == nullptr || entity->session == nullptr) { + HILOGE("object is invalid"); + return -E_PARAMS; + } + std::string bundle = AniUtils::AniStringToStdString(aniEnv, bundleName); + return entity->session->CleanBundleTempDir(bundle); +} + +void IncrBackupSessionCleaner::Clean(ani_env *aniEnv, ani_object object) +{ + ani_status ret = ANI_ERROR; + ani_long session {}; + if ((ret = aniEnv->Object_GetPropertyByName_Long(object, "session", &session)) != ANI_OK) { + HILOGE("get field session failed, ret:%{public}d", ret); + } else { + BIncrementalBackupSession* sessionPtr = reinterpret_cast(session); + if (sessionPtr != nullptr) { + delete sessionPtr; + } + } + ani_long callbacks {}; + if ((ret = aniEnv->Object_GetPropertyByName_Long(object, "callbacks", &callbacks)) != ANI_OK) { + HILOGE("get field callbacks failed, ret:%{public}d", ret); + } else { + GeneralCallbacks* callbackPtr = reinterpret_cast(callbacks); + if (callbackPtr != nullptr) { + delete callbackPtr; + } + } +} +} diff --git a/interfaces/kits/ani/utils/include/ani_utils.h b/interfaces/kits/ani/utils/include/ani_utils.h new file mode 100644 index 0000000000000000000000000000000000000000..38de703c0f7b2a18f3cfd742bca157f33be31c89 --- /dev/null +++ b/interfaces/kits/ani/utils/include/ani_utils.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANI_UTILS_H +#define ANI_UTILS_H + +#include +#include +#include +#include +#include + +#include + +namespace OHOS::FileManagement::Backup { +class AniUtils { +public: + static std::string AniStringToStdString(ani_env* env, ani_string aniString); + static bool AniObjectToStdString(ani_env* env, ani_object obj, std::string& str); + static std::optional StdStringToAniString(ani_env* env, const std::string& str); + static bool AniArrayToStrVector(ani_env* env, ani_array arr, std::vector& result); + static ani_class GetAniClsByName(ani_env* env, std::string className); +private: + static std::unordered_map clsMap_; + static std::mutex mapMutex_; +}; +} // namespace OHOS::FileManagement::Backup +#endif // ANI_UTILS_H \ No newline at end of file diff --git a/interfaces/kits/ani/utils/src/ani_utils.cpp b/interfaces/kits/ani/utils/src/ani_utils.cpp new file mode 100644 index 0000000000000000000000000000000000000000..89025e110a0222b65b13b771a20256b0005652ab --- /dev/null +++ b/interfaces/kits/ani/utils/src/ani_utils.cpp @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ani_utils.h" +#include "filemgmt_libhilog.h" + +namespace OHOS::FileManagement::Backup { +std::unordered_map AniUtils::clsMap_; +std::mutex AniUtils::mapMutex_; + +std::string AniUtils::AniStringToStdString(ani_env *env, ani_string aniString) +{ + ani_size sz {}; + env->String_GetUTF8Size(aniString, &sz); + + std::string result(sz + 1, 0); + env->String_GetUTF8(aniString, result.data(), result.size(), &sz); + result.resize(sz); + return result; +} + +bool AniUtils::AniObjectToStdString(ani_env* env, ani_object obj, std::string& str) +{ + ani_class stringClass = GetAniClsByName(env, "std.core.String"); + ani_boolean isString = ANI_FALSE; + env->Object_InstanceOf(obj, stringClass, &isString); + if (!isString) { + HILOGE("obj is not ani_string"); + return false; + } + str = AniStringToStdString(env, static_cast(obj)); + return true; +} + +std::optional AniUtils::StdStringToAniString(ani_env *env, const std::string& str) +{ + ani_string result_string{}; + if (env->String_NewUTF8(str.c_str(), str.size(), &result_string) != ANI_OK) { + return {}; + } + return result_string; +} + +bool AniUtils::AniArrayToStrVector(ani_env* env, ani_array arr, std::vector& result) +{ + ani_size arrSize = 0; + if (ANI_OK != env->Array_GetLength(arr, &arrSize)) { + HILOGE("Array_GetLength fail"); + return false; + } + if (arrSize == 0) { + return true; + } + for (ani_size idx = 0; idx < arrSize; idx++) { + ani_ref item; + if (ANI_OK != env->Array_Get(arr, idx, &item)) { + HILOGE("Array_Get fail, idx=%{public}zu", idx); + return false; + } + std::string str; + if (!AniObjectToStdString(env, static_cast(item), str)) { + HILOGE("ani_ref cast to string fail, idx=%{public}zu", idx); + return false; + } + result.push_back(str); + } + return true; +} + +ani_class AniUtils::GetAniClsByName(ani_env* env, std::string className) +{ + std::lock_guard lock(mapMutex_); + if (clsMap_.count(className) > 0) { + return clsMap_[className]; + } + ani_class cls {}; + if (ANI_OK != env->FindClass(className.c_str(), &cls)) { + HILOGE("find class fail, class=%{public}s", className.c_str()); + return nullptr; + } + clsMap_[className] = cls; + return cls; +} +} \ No newline at end of file diff --git a/interfaces/kits/js/BUILD.gn b/interfaces/kits/js/BUILD.gn index 3a96c145cde353a7467aa2e139221e18a3697381..1d42a96850b0f45d5f753e09d0668a85f5a2b742 100644 --- a/interfaces/kits/js/BUILD.gn +++ b/interfaces/kits/js/BUILD.gn @@ -121,7 +121,6 @@ ohos_shared_library("fileuri") { use_exceptions = true relative_install_dir = "module/file" - part_name = "app_file_service" subsystem_name = "filemanagement" } @@ -145,11 +144,60 @@ ohos_shared_library("backup") { ] sources = [ - "backup/general_callbacks.cpp", "backup/module.cpp", - "backup/parse_inc_info_from_js.cpp", "backup/prop_n_exporter.cpp", "backup/prop_n_operation.cpp", + ] + + deps = [ + "${path_backup}/interfaces/inner_api/native/backup_kit_inner:backup_kit_inner", + "${path_backup}/services/backup_sa:backup_sa_ipc", + "${path_backup}/utils:backup_utils", + "${app_file_service_path}/interfaces/kits/js:backup_inner", + ] + + cflags_cc = [ + "-fdata-sections", + "-ffunction-sections", + "-fno-unwind-tables", + "-fno-asynchronous-unwind-tables", + "-Os", + ] + + external_deps = [ + "access_token:libaccesstoken_sdk", + "access_token:libtokenid_sdk", + "c_utils:utils", + "file_api:filemgmt_libhilog", + "file_api:filemgmt_libn", + "hilog:libhilog", + "ipc:ipc_core", + "jsoncpp:jsoncpp", + "napi:ace_napi", + "samgr:samgr_proxy", + ] +} + +ohos_shared_library("backup_inner") { + branch_protector_ret = "pac_ret" + sanitize = { + integer_overflow = true + cfi = true + cfi_cross_dso = true + debug = false + } + + subsystem_name = "filemanagement" + part_name = "app_file_service" + + defines = [ + "LOG_DOMAIN=0xD004306", + "LOG_TAG=\"BackupNAPI\"", + ] + + sources = [ + "backup/general_callbacks.cpp", + "backup/parse_inc_info_from_js.cpp", "backup/session_backup_n_exporter.cpp", "backup/session_incremental_backup_n_exporter.cpp", "backup/session_restore_n_exporter.cpp", diff --git a/interfaces/kits/js/backup/session_incremental_backup_n_exporter.cpp b/interfaces/kits/js/backup/session_incremental_backup_n_exporter.cpp index 6c7c377fd9611ed8416ba5f361d8b889ac7283d1..3c525df4df4ed4e35fac43bc4acf3630e27df734 100644 --- a/interfaces/kits/js/backup/session_incremental_backup_n_exporter.cpp +++ b/interfaces/kits/js/backup/session_incremental_backup_n_exporter.cpp @@ -15,18 +15,15 @@ #include "session_incremental_backup_n_exporter.h" #include -#include #include "b_error/b_error.h" #include "b_filesystem/b_file.h" -#include "b_incremental_backup_session.h" #include "b_incremental_data.h" #include "b_resources/b_constants.h" #include "b_sa/b_sa_utils.h" #include "backup_kit_inner.h" #include "directory_ex.h" #include "filemgmt_libhilog.h" -#include "general_callbacks.h" #include "incremental_backup_data.h" #include "parse_inc_info_from_js.h" #include "service_proxy.h" @@ -35,10 +32,8 @@ namespace OHOS::FileManagement::Backup { using namespace std; using namespace LibN; -struct BackupEntity { - unique_ptr session; - shared_ptr callbacks; -}; +const std::string CLASS_NAME = "IncrementalBackupSession"; +const std::string NAPI_CLASS_NAME = "NapiIncrementalBackupSession"; static void OnFileReady(weak_ptr pCallbacks, const BFileInfo &fileInfo, UniqueFd fd, UniqueFd manifestFd, int sysErrno) @@ -300,10 +295,11 @@ static void OnProcess(weak_ptr pCallbacks, const BundleName na callbacks->onProcess.CallJsMethod(cbCompl); } -static bool SetIncrementalBackupEntity(napi_env env, NFuncArg &funcArg, std::unique_ptr backupEntity) +static bool SetIncrementalBackupEntity(napi_env env, NFuncArg &funcArg, std::unique_ptr backupEntity) { auto finalize = [](napi_env env, void *data, void *hint) { - std::unique_ptr entity = std::unique_ptr(static_cast(data)); + std::unique_ptr entity = + std::unique_ptr(static_cast(data)); if (entity == nullptr) { HILOGE("Entity is nullptr"); return; @@ -315,7 +311,7 @@ static bool SetIncrementalBackupEntity(napi_env env, NFuncArg &funcArg, std::uni entity->callbacks->RemoveCallbackRef(); }; if (napi_wrap(env, funcArg.GetThisVar(), backupEntity.release(), finalize, nullptr, nullptr) != napi_ok) { - HILOGE("Failed to set BackupEntity entity."); + HILOGE("Failed to set IncrBackupEntity entity."); return false; } return true; @@ -367,7 +363,7 @@ napi_value SessionIncrementalBackupNExporter::Constructor(napi_env env, napi_cal return nullptr; } NVal ptr(env, funcArg.GetThisVar()); - auto backupEntity = std::make_unique(); + auto backupEntity = std::make_unique(); backupEntity->callbacks = make_shared(env, ptr, callbacks); ErrCode errCode; std::string errMsg; @@ -389,7 +385,7 @@ napi_value SessionIncrementalBackupNExporter::Constructor(napi_env env, napi_cal return nullptr; } if (!SetIncrementalBackupEntity(env, funcArg, std::move(backupEntity))) { - NError(BError(BError::Codes::SDK_INVAL_ARG, "Failed to set BackupEntity entity.").GetCode()).ThrowErr(env); + NError(BError(BError::Codes::SDK_INVAL_ARG, "Failed to set IncrBackupEntity entity.").GetCode()).ThrowErr(env); return nullptr; } HILOGD("called SessionIncrementalBackup::Constructor end"); @@ -415,7 +411,7 @@ napi_value SessionIncrementalBackupNExporter::GetLocalCapabilities(napi_env env, NError(BError(BError::Codes::SDK_INVAL_ARG, "Number of arguments unmatched.").GetCode()).ThrowErr(env); return nullptr; } - auto backupEntity = NClass::GetEntityOf(env, funcArg.GetThisVar()); + auto backupEntity = NClass::GetEntityOf(env, funcArg.GetThisVar()); if (!(backupEntity && backupEntity->session)) { HILOGE("Failed to get backupSession entity."); NError(BError(BError::Codes::SDK_INVAL_ARG, "Failed to get backupSession entity.").GetCode()).ThrowErr(env); @@ -435,7 +431,7 @@ napi_value SessionIncrementalBackupNExporter::GetLocalCapabilities(napi_env env, return {obj}; }; NVal thisVar(env, funcArg.GetThisVar()); - return NAsyncWorkPromise(env, thisVar).Schedule(className, cbExec, cbCompl).val_; + return NAsyncWorkPromise(env, thisVar).Schedule(CLASS_NAME, cbExec, cbCompl).val_; } napi_value SessionIncrementalBackupNExporter::GetBackupDataSize(napi_env env, napi_callback_info cbinfo) @@ -458,7 +454,7 @@ napi_value SessionIncrementalBackupNExporter::GetBackupDataSize(napi_env env, na HILOGE("VerifyAndParseParams failed"); return nullptr; } - auto backupEntity = NClass::GetEntityOf(env, funcArg.GetThisVar()); + auto backupEntity = NClass::GetEntityOf(env, funcArg.GetThisVar()); if (!(backupEntity && backupEntity->session)) { HILOGE("Failed to get backupSession entity."); NError(BError(BError::Codes::SDK_INVAL_ARG, "Failed to get backupSession entity.").GetCode()).ThrowErr(env); @@ -480,7 +476,7 @@ napi_value SessionIncrementalBackupNExporter::GetBackupDataSize(napi_env env, na return err ? NVal {env, err.GetNapiErr(env)} : NVal::CreateUndefined(env); }; NVal thisVar(env, funcArg.GetThisVar()); - return NAsyncWorkPromise(env, thisVar).Schedule(className, cbExec, cbCompl).val_; + return NAsyncWorkPromise(env, thisVar).Schedule(CLASS_NAME, cbExec, cbCompl).val_; } static bool VerifyParamSuccess(NFuncArg &funcArg, std::vector &backupBundles, @@ -536,7 +532,7 @@ napi_value SessionIncrementalBackupNExporter::AppendBundles(napi_env env, napi_c HILOGE("VerifyParamSuccess fail"); return nullptr; } - auto backupEntity = NClass::GetEntityOf(env, funcArg.GetThisVar()); + auto backupEntity = NClass::GetEntityOf(env, funcArg.GetThisVar()); if (!(backupEntity && backupEntity->session)) { HILOGE("Failed to get backupSession entity."); NError(BError(BError::Codes::SDK_INVAL_ARG, "Failed to get backupSession entity.").GetCode()).ThrowErr(env); @@ -557,12 +553,12 @@ napi_value SessionIncrementalBackupNExporter::AppendBundles(napi_env env, napi_c }; NVal thisVar(env, funcArg.GetThisVar()); if (funcArg.GetArgc() == NARG_CNT::ONE) { - return NAsyncWorkPromise(env, thisVar).Schedule(className, cbExec, cbCompl).val_; + return NAsyncWorkPromise(env, thisVar).Schedule(CLASS_NAME, cbExec, cbCompl).val_; } else if (!bundleInfos.empty()) { - return NAsyncWorkPromise(env, thisVar).Schedule(className, cbExec, cbCompl).val_; + return NAsyncWorkPromise(env, thisVar).Schedule(CLASS_NAME, cbExec, cbCompl).val_; } else { NVal cb(env, funcArg[NARG_POS::SECOND]); - return NAsyncWorkCallback(env, thisVar, cb).Schedule(className, cbExec, cbCompl).val_; + return NAsyncWorkCallback(env, thisVar, cb).Schedule(CLASS_NAME, cbExec, cbCompl).val_; } } @@ -586,7 +582,7 @@ napi_value SessionIncrementalBackupNExporter::Release(napi_env env, napi_callbac return nullptr; } - auto backupEntity = NClass::GetEntityOf(env, funcArg.GetThisVar()); + auto backupEntity = NClass::GetEntityOf(env, funcArg.GetThisVar()); if (!(backupEntity && backupEntity->session)) { HILOGE("Failed to get backupSession entity."); NError(BError(BError::Codes::SDK_INVAL_ARG, "Failed to get backupSession entity.").GetCode()).ThrowErr(env); @@ -606,7 +602,7 @@ napi_value SessionIncrementalBackupNExporter::Release(napi_env env, napi_callbac HILOGD("Called SessionIncrementalBackup::Release end."); NVal thisVar(env, funcArg.GetThisVar()); - return NAsyncWorkPromise(env, thisVar).Schedule(className, cbExec, cbCompl).val_; + return NAsyncWorkPromise(env, thisVar).Schedule(CLASS_NAME, cbExec, cbCompl).val_; } napi_value SessionIncrementalBackupNExporter::Cancel(napi_env env, napi_callback_info info) @@ -637,7 +633,7 @@ napi_value SessionIncrementalBackupNExporter::Cancel(napi_env env, napi_callback } std::string bundleName = bundle.get(); - auto backupEntity = NClass::GetEntityOf(env, funcArg.GetThisVar()); + auto backupEntity = NClass::GetEntityOf(env, funcArg.GetThisVar()); if (!(backupEntity && backupEntity->session)) { HILOGE("Failed to get backupSession entity."); return nullptr; @@ -657,7 +653,7 @@ napi_value SessionIncrementalBackupNExporter::Cancel(napi_env env, napi_callback static NContextCBExec CleanBundleTempDirCBExec(napi_env env, const NFuncArg &funcArg, std::unique_ptr bundleName) { - auto backupEntity = NClass::GetEntityOf(env, funcArg.GetThisVar()); + auto backupEntity = NClass::GetEntityOf(env, funcArg.GetThisVar()); if (!(backupEntity && (backupEntity->session))) { HILOGE("Failed to get BackupSession entity."); NError(BError(BError::Codes::SDK_INVAL_ARG, "Failed to get BackupSession entity.").GetCode()).ThrowErr(env); @@ -708,7 +704,7 @@ napi_value SessionIncrementalBackupNExporter::CleanBundleTempDir(napi_env env, n }; NVal thisVar(env, funcArg.GetThisVar()); - return NAsyncWorkPromise(env, thisVar).Schedule(className, cbExec, cbCompl).val_; + return NAsyncWorkPromise(env, thisVar).Schedule(CLASS_NAME, cbExec, cbCompl).val_; } bool SessionIncrementalBackupNExporter::Export() @@ -723,13 +719,13 @@ bool SessionIncrementalBackupNExporter::Export() NVal::DeclareNapiFunction("cleanBundleTempDir", CleanBundleTempDir), }; - auto [succ, classValue] = NClass::DefineClass(exports_.env_, className, Constructor, std::move(props)); + auto [succ, classValue] = NClass::DefineClass(exports_.env_, CLASS_NAME, Constructor, std::move(props)); if (!succ) { HILOGE("Failed to define class"); NError(EIO).ThrowErr(exports_.env_); return false; } - succ = NClass::SaveClass(exports_.env_, className, classValue); + succ = NClass::SaveClass(exports_.env_, CLASS_NAME, classValue); if (!succ) { HILOGE("Failed to save class"); NError(EIO).ThrowErr(exports_.env_); @@ -737,12 +733,103 @@ bool SessionIncrementalBackupNExporter::Export() } HILOGD("called SessionIncrementalBackupNExporter::Export end"); - return exports_.AddProp(className, classValue); + return exports_.AddProp(CLASS_NAME, classValue); +} + +napi_value SessionIncrementalBackupNExporter::ConstructorFromEntity(napi_env env, napi_callback_info cbinfo) +{ + HILOGD("called ConstructorFromEntity begin"); + if (!SAUtils::CheckBackupPermission()) { + NError(E_PERMISSION).ThrowErr(env); + return nullptr; + } + if (!SAUtils::IsSystemApp()) { + NError(E_PERMISSION_SYS).ThrowErr(env); + return nullptr; + } + NFuncArg funcArg(env, cbinfo); + if (!funcArg.InitArgs(NARG_CNT::ONE)) { + NError(BError(BError::Codes::SDK_INVAL_ARG, "Number of arguments unmatched.").GetCode()).ThrowErr(env); + return nullptr; + } + void* entityRawPtr = nullptr; + if (napi_ok != napi_get_value_external(env, funcArg[NARG_POS::FIRST], &entityRawPtr)) { + HILOGE("parse entity raw ptr for napi_value fail"); + return nullptr; + } + IncrBackupEntity* entity = reinterpret_cast(entityRawPtr); + if (entity == nullptr) { + NError(BError(BError::Codes::SDK_INVAL_ARG, "First argument is not session pointer.").GetCode()).ThrowErr(env); + return nullptr; + } + std::unique_ptr backupEntity(entity); + if (backupEntity->session == nullptr || backupEntity->callbacks == nullptr) { + HILOGD("session or callback is null"); + return nullptr; + } + if (!SetIncrementalBackupEntity(env, funcArg, std::move(backupEntity))) { + NError(BError(BError::Codes::SDK_INVAL_ARG, "Failed to set IncrBackupEntity entity.").GetCode()).ThrowErr(env); + return nullptr; + } + HILOGD("called ConstructorFromEntity end"); + return funcArg.GetThisVar(); +} + +napi_value SessionIncrementalBackupNExporter::CreateByEntity(napi_env env, IncrBackupEntity* entity) +{ + HILOGD("CreateByEntity begin"); + if (entity == nullptr) { + HILOGE("entity is null"); + return nullptr; + } + vector props = { + NVal::DeclareNapiFunction("getLocalCapabilities", GetLocalCapabilities), + NVal::DeclareNapiFunction("getBackupDataSize", GetBackupDataSize), + NVal::DeclareNapiFunction("appendBundles", AppendBundles), + NVal::DeclareNapiFunction("release", Release), + NVal::DeclareNapiFunction("cancel", Cancel), + NVal::DeclareNapiFunction("cleanBundleTempDir", CleanBundleTempDir), + }; + auto [defRet, constroctor] = NClass::DefineClass(env, NAPI_CLASS_NAME, ConstructorFromEntity, + std::move(props)); + if (!defRet) { + HILOGE("Failed to define class"); + return nullptr; + } + napi_value instance; + napi_value napiEntity; + auto finalize = [](napi_env env, void *data, void *hint) { + std::unique_ptr entity = + std::unique_ptr(static_cast(data)); + if (entity == nullptr) { + HILOGE("Entity is nullptr"); + return; + } + if (entity->callbacks == nullptr) { + HILOGE("Callbacks is nullptr"); + return; + } + entity->callbacks->RemoveCallbackRef(); + }; + if (napi_ok != napi_create_external(env, (void *)entity, finalize, nullptr, &napiEntity)) { + HILOGE("wrap entity prt fail"); + return nullptr; + } + size_t argc = 1; + napi_value args[1] = { napiEntity }; + + napi_status napiStatus = napi_new_instance(env, constroctor, argc, args, &instance); + if (napi_status::napi_ok != napiStatus) { + HILOGE("Failed to napi_new_instance, status=%{public}d", napiStatus); + return nullptr; + } + HILOGD("CreateByEntity end"); + return instance; } string SessionIncrementalBackupNExporter::GetClassName() { - return SessionIncrementalBackupNExporter::className; + return CLASS_NAME; } SessionIncrementalBackupNExporter::SessionIncrementalBackupNExporter(napi_env env, napi_value exports) diff --git a/interfaces/kits/js/backup/session_incremental_backup_n_exporter.h b/interfaces/kits/js/backup/session_incremental_backup_n_exporter.h index 7f9547232f0fef20da12c0bdcb05b6fca8b11d1e..a75655e8f5bdd9ccbf5fbcdf7981a08ecffd98b5 100644 --- a/interfaces/kits/js/backup/session_incremental_backup_n_exporter.h +++ b/interfaces/kits/js/backup/session_incremental_backup_n_exporter.h @@ -15,13 +15,20 @@ #ifndef INTERFACES_KITS_JS_SRC_MOD_BACKUP_PROPERTIES_SESSION_INCREMENTAL_BACKUP_N_EXPORTER_H #define INTERFACES_KITS_JS_SRC_MOD_BACKUP_PROPERTIES_SESSION_INCREMENTAL_BACKUP_N_EXPORTER_H +#include + +#include "b_incremental_backup_session.h" +#include "general_callbacks.h" #include "n_exporter.h" namespace OHOS::FileManagement::Backup { +struct IncrBackupEntity { + std::unique_ptr session; + std::shared_ptr callbacks; +}; + class SessionIncrementalBackupNExporter final : public LibN::NExporter { public: - inline static const std::string className = "IncrementalBackupSession"; - bool Export() override; std::string GetClassName() override; @@ -33,6 +40,9 @@ public: static napi_value Cancel(napi_env env, napi_callback_info cbinfo); static napi_value CleanBundleTempDir(napi_env env, napi_callback_info cbinfo); + static napi_value ConstructorFromEntity(napi_env env, napi_callback_info cbinfo); + static napi_value CreateByEntity(napi_env env, IncrBackupEntity* entity); + SessionIncrementalBackupNExporter(napi_env env, napi_value exports); ~SessionIncrementalBackupNExporter() override; };