From 3517d531661bf41664c4d1d1a90ded9d74dbf61f Mon Sep 17 00:00:00 2001 From: xushunjie Date: Mon, 28 Apr 2025 10:40:31 +0800 Subject: [PATCH] =?UTF-8?q?fileuri=20nativeptr=E6=94=B9=E9=80=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: I2381660a80244f09e49d373e0d4b33c844ce5c07 Signed-off-by: xushunjie --- interfaces/kits/ani/file_uri/BUILD.gn | 1 + .../ani/file_uri/ets/@ohos.file.fileuri.ets | 43 ++++++ .../file_uri/include/ani_util_native_ptr.h | 144 ++++++++++++++++++ .../kits/ani/file_uri/src/ani_file_uri.cpp | 24 ++- 4 files changed, 208 insertions(+), 4 deletions(-) create mode 100644 interfaces/kits/ani/file_uri/include/ani_util_native_ptr.h diff --git a/interfaces/kits/ani/file_uri/BUILD.gn b/interfaces/kits/ani/file_uri/BUILD.gn index 7fad45cea..bd7dd815c 100644 --- a/interfaces/kits/ani/file_uri/BUILD.gn +++ b/interfaces/kits/ani/file_uri/BUILD.gn @@ -32,6 +32,7 @@ ohos_shared_library("fileuri_ani") { ] include_dirs = [ + "include", "../../../common/include", "../../js/file_uri", "${app_file_service_path}/interfaces/innerkits/native/file_uri/include", diff --git a/interfaces/kits/ani/file_uri/ets/@ohos.file.fileuri.ets b/interfaces/kits/ani/file_uri/ets/@ohos.file.fileuri.ets index 0e2afd40d..fa37dd46b 100644 --- a/interfaces/kits/ani/file_uri/ets/@ohos.file.fileuri.ets +++ b/interfaces/kits/ani/file_uri/ets/@ohos.file.fileuri.ets @@ -15,6 +15,42 @@ import uri from '@ohos.uri'; +class Cleaner { + static callback(cleaner: Cleaner): void { + console.println("enter Cleaner.callback"); + cleaner.clean() + } + + constructor(targetPtr: long) { + this.targetPtr = targetPtr + } + + native clean(): void + + private targetPtr: long = 0 +}; + +class FinalizationAgent { + constructor(obj: T, ptr: long) { + this.register(obj, ptr); + } + + register(obj: T, ptr: long): void { + this.unregisterToken = {}; + this.cleaner = new Cleaner(ptr); + finalizer.register(obj, this.cleaner!, this.unregisterToken); + } + + unregister(): void { + finalizer.unregister(this.unregisterToken); + } + + private cleaner: Cleaner | null = null; + private unregisterToken: object = {}; +} + +let finalizer = new FinalizationRegistry(Cleaner.callback) + export default namespace fileUri { loadLibrary("fileuri_ani") @@ -27,7 +63,14 @@ export default namespace fileUri { private fileUriEntity_: long = 0; private acquireFileUriEntity(fileUriEntity: long) { this.fileUriEntity_ = fileUriEntity; + this.fzAgent = new FinalizationAgent(this, this.fileUriEntity_); } + + unregisterCleaner(): void { + this.fzAgent.unregister(); + } + + private fzAgent: FinalizationAgent; }; export native function getUriFromPath(path: string): string; } diff --git a/interfaces/kits/ani/file_uri/include/ani_util_native_ptr.h b/interfaces/kits/ani/file_uri/include/ani_util_native_ptr.h new file mode 100644 index 000000000..014325ea5 --- /dev/null +++ b/interfaces/kits/ani/file_uri/include/ani_util_native_ptr.h @@ -0,0 +1,144 @@ +/* + * 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_UTIL_OBJECT_H +#define ANI_UTIL_OBJECT_H + +#include +#include + +#include +#include + +class NativeObject { +public: + virtual ~NativeObject() = default; +}; + + +template +class StdSharedPtrHolder : public NativeObject { +public: + StdSharedPtrHolder(const std::shared_ptr &sptr) : sptr_(sptr) + { + } + + std::shared_ptr Get() + { + return sptr_; + } + + std::shared_ptr GetOrDefault() + { + if (!sptr_) { + sptr_ = std::make_shared(); + } + return sptr_; + } + +private: + std::shared_ptr sptr_; +}; + + +template +class OhSharedPtrHolder : public NativeObject { +public: + OhSharedPtrHolder(const OHOS::sptr &sptr) : sptr_(sptr) + { + } + + OHOS::sptr Get() + { + return sptr_; + } + + OHOS::sptr GetOrDefault() + { + if (!sptr_) { + sptr_ = OHOS::sptr::MakeSptr(); + } + return sptr_; + } + +private: + OHOS::sptr sptr_; +}; + + +class NativePtrWrapper { +public: + NativePtrWrapper(ani_env *env, ani_object object, const char* propName = "nativePtr") + : env_(env), obj_(object), propName_(propName) + { + } + + template + ani_status Wrap(T* nativePtr) + { + return env_->Object_SetFieldByName_Long(obj_, propName_.c_str(), reinterpret_cast(nativePtr)); + } + + template + T* Unwrap() + { + ani_long nativePtr; + if (ANI_OK != env_->Object_GetFieldByName_Long(obj_, propName_.c_str(), &nativePtr)) { + return nullptr; + } + return reinterpret_cast(nativePtr); + } + +private: + ani_env *env_ = nullptr; + ani_object obj_ = nullptr; + std::string propName_; +}; + + +class NativePtrCleaner { +public: + static void Clean([[maybe_unused]] ani_env *env, [[maybe_unused]] ani_object object) + { + ani_long ptr = 0; + if (ANI_OK != env->Object_GetFieldByName_Long(object, "targetPtr", &ptr)) { + return; + } + delete reinterpret_cast(ptr); + } + + NativePtrCleaner(ani_env *env) + : env_(env) + { + } + + ani_status Bind(ani_class cls) + { + std::array methods = { + ani_native_function { "clean", nullptr, reinterpret_cast(NativePtrCleaner::Clean) }, + }; + + if (ANI_OK != env_->Class_BindNativeMethods(cls, methods.data(), methods.size())) { + return (ani_status)ANI_ERROR; + }; + + return ANI_OK; + } + +private: + ani_env *env_ = nullptr; +}; + +#endif diff --git a/interfaces/kits/ani/file_uri/src/ani_file_uri.cpp b/interfaces/kits/ani/file_uri/src/ani_file_uri.cpp index e7f181117..8ba4067de 100644 --- a/interfaces/kits/ani/file_uri/src/ani_file_uri.cpp +++ b/interfaces/kits/ani/file_uri/src/ani_file_uri.cpp @@ -21,6 +21,7 @@ #include "file_utils.h" #include "log.h" #include "n_error.h" +#include "ani_util_native_ptr.h" using namespace OHOS::AppFileService; @@ -41,11 +42,17 @@ static std::string ParseObjToStr(ani_env *env, ani_string stringObj) static ModuleFileUri::FileUriEntity *unwrapp(ani_env *env, ani_object object) { - ani_long fileuriEntity_; - if (ANI_OK != env->Object_GetFieldByName_Long(object, "fileUriEntity_", &fileuriEntity_)) { + ani_long fileUriEntityHolder_; + if (ANI_OK != env->Object_GetFieldByName_Long(object, "fileUriEntity_", &fileUriEntityHolder_)) { + LOGE("Get fileuriEntityHolder_ failed"); return nullptr; } - return reinterpret_cast(fileuriEntity_); + auto fileUriHolder = reinterpret_cast *>(fileUriEntityHolder_); + if (!fileUriHolder) { + LOGE("Get fileuriEntityHolder by long ptr failed"); + return nullptr; + } + return reinterpret_cast(fileUriHolder->Get().get()); } static void ThrowBusinessError(ani_env *env, int errCode, std::string&& errMsg) @@ -120,6 +127,8 @@ void FileUriConstructor(ani_env *env, ani_object obj, ani_string stringObj) return; } LOGD("FileUriConstructor fileuriEntity: %{public}p.", fileuriEntity.get()); + StdSharedPtrHolder *holder + = new StdSharedPtrHolder(std::move(fileuriEntity)); ani_namespace ns; if (env->FindNamespace("L@ohos/file/fileuri/fileUri;", &ns) != ANI_OK) { @@ -143,7 +152,7 @@ void FileUriConstructor(ani_env *env, ani_object obj, ani_string stringObj) return; } - if (ANI_OK != env->Object_CallMethod_Void(obj, acquireObj, reinterpret_cast(fileuriEntity.get()))) { + if (ANI_OK != env->Object_CallMethod_Void(obj, acquireObj, reinterpret_cast(holder))) { LOGE("Call method acquireFileUriEntity failed."); ThrowBusinessError(env, EPERM, "Call method acquireFileUriEntity failed."); return; @@ -187,6 +196,13 @@ ANI_EXPORT ani_status ANI_Constructor(ani_vm *vm, uint32_t *result) return ANI_ERROR; }; + ani_class cleanerCls; + if (ANI_OK != env->FindClass("L@ohos/file/fileuri/Cleaner;", &cleanerCls)) { + LOGE("Not found class @ohos/file/fileuri/Cleaner;."); + return ANI_NOT_FOUND; + } + NativePtrCleaner(env).Bind(cleanerCls); + *result = ANI_VERSION_1; return ANI_OK; } -- Gitee