1 /* 2 * Copyright (c) 2025 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 #ifndef INTERFACES_KITS_JS_SRC_COMMON_ANI_HELPER_ANI_HELPER_H 17 #define INTERFACES_KITS_JS_SRC_COMMON_ANI_HELPER_ANI_HELPER_H 18 19 #include <optional> 20 #include <string> 21 #include <tuple> 22 23 #include <ani.h> 24 25 #include "ani_signature.h" 26 #include "event_handler.h" 27 #include "event_runner.h" 28 #include "file_utils.h" 29 #include "filemgmt_libhilog.h" 30 #include "type_converter.h" 31 32 namespace OHOS::FileManagement::ModuleFileIO::ANI { 33 using namespace std; 34 using namespace OHOS::FileManagement::ModuleFileIO::ANI::AniSignature; 35 36 class AniHelper { 37 public: 38 template <typename T> SetFieldValue(ani_env * env,const ani_class & cls,ani_object & obj,const char * fieldName,const T & value)39 static ani_status SetFieldValue( 40 ani_env *env, const ani_class &cls, ani_object &obj, const char *fieldName, const T &value) 41 { 42 ani_field field; 43 auto status = env->Class_FindField(cls, fieldName, &field); 44 if (status != ANI_OK) { 45 return status; 46 } 47 48 if constexpr (is_same_v<T, int> || is_same_v<T, int32_t> || is_same_v<T, ani_int>) { 49 status = env->Object_SetField_Int(obj, field, value); 50 } else if constexpr (is_same_v<T, int64_t> || is_same_v<T, ani_long>) { 51 status = env->Object_SetField_Long(obj, field, value); 52 } else if constexpr (is_same_v<T, double> || is_same_v<T, ani_double>) { 53 status = env->Object_SetField_Double(obj, field, value); 54 } else if constexpr (is_same_v<T, bool> || is_same_v<T, ani_boolean>) { 55 status = env->Object_SetField_Boolean(obj, field, value); 56 } else if constexpr (is_same_v<T, string> || is_same_v<T, const char *>) { 57 auto [succ, aniStr] = TypeConverter::ToAniString(env, value); 58 if (!succ) { 59 return ANI_ERROR; 60 } 61 status = env->Object_SetField_Ref(obj, field, move(aniStr)); 62 } else if constexpr (is_base_of_v<ani_ref, T>) { 63 status = env->Object_SetField_Ref(obj, field, value); 64 } else { 65 return ANI_INVALID_TYPE; 66 } 67 return status; 68 } 69 70 template <typename T> SetPropertyValue(ani_env * env,const ani_class & cls,ani_object & obj,const string & property,const T & value)71 static ani_status SetPropertyValue( 72 ani_env *env, const ani_class &cls, ani_object &obj, const string &property, const T &value) 73 { 74 ani_method method; 75 string setter = "<set>" + property; 76 auto status = env->Class_FindMethod(cls, setter.c_str(), nullptr, &method); 77 if (status != ANI_OK) { 78 return status; 79 } 80 81 if constexpr (is_same_v<T, string> || is_same_v<T, const char *>) { 82 auto [succ, aniStr] = TypeConverter::ToAniString(env, value); 83 if (!succ) { 84 return ANI_ERROR; 85 } 86 status = env->Object_CallMethod_Void(obj, method, move(aniStr)); 87 } else if constexpr (is_base_of_v<ani_ref, T> || is_same_v<T, int> || is_same_v<T, int32_t> || 88 is_same_v<T, ani_int> || is_same_v<T, int64_t> || is_same_v<T, ani_long> || 89 is_same_v<T, double> || is_same_v<T, ani_double> || is_same_v<T, bool> || 90 is_same_v<T, ani_boolean>) { 91 status = env->Object_CallMethod_Void(obj, method, value); 92 } else { 93 return ANI_INVALID_TYPE; 94 } 95 return status; 96 } 97 ParseInt64Option(ani_env * env,ani_object obj,const string & tag)98 static tuple<bool, optional<int64_t>> ParseInt64Option(ani_env *env, ani_object obj, const string &tag) 99 { 100 ani_boolean isUndefined = true; 101 ani_ref property; 102 ani_status status = ANI_ERROR; 103 status = env->Object_GetPropertyByName_Ref(obj, tag.c_str(), &property); 104 if (status != ANI_OK) { 105 return { false, nullopt }; 106 } 107 env->Reference_IsUndefined(property, &isUndefined); 108 if (isUndefined) { 109 return { true, nullopt }; 110 } 111 static const string longValueSig = Builder::BuildSignatureDescriptor({}, BasicTypes::longType); 112 ani_long value; 113 status = env->Object_CallMethodByName_Long( 114 static_cast<ani_object>(property), BasicTypesConverter::toLong.c_str(), longValueSig.c_str(), &value); 115 if (status != ANI_OK) { 116 return { false, nullopt }; 117 } 118 auto result = make_optional<int64_t>(static_cast<int64_t>(value)); 119 return { true, move(result) }; 120 } 121 ParseEncoding(ani_env * env,ani_object obj)122 static tuple<bool, optional<string>> ParseEncoding(ani_env *env, ani_object obj) 123 { 124 ani_boolean isUndefined; 125 ani_ref property; 126 if (ANI_OK != env->Object_GetPropertyByName_Ref(obj, "encoding", &property)) { 127 return { false, nullopt }; 128 } 129 env->Reference_IsUndefined(property, &isUndefined); 130 if (isUndefined) { 131 return { true, nullopt }; 132 } 133 auto [succ, encoding] = TypeConverter::ToUTF8String(env, (ani_string)property); 134 if (!succ) { 135 return { false, nullopt }; 136 } 137 return { true, make_optional<string>(move(encoding)) }; 138 } 139 GetThreadEnvStorage()140 static ani_env *&GetThreadEnvStorage() 141 { 142 static thread_local ani_env *env { nullptr }; 143 return env; 144 } 145 GetThreadEnv(ani_vm * vm)146 static ani_env *GetThreadEnv(ani_vm *vm) 147 { 148 auto &env = GetThreadEnvStorage(); 149 if (env != nullptr) { 150 return env; 151 } 152 153 ani_options aniArgs { 0, nullptr }; 154 auto status = vm->AttachCurrentThread(&aniArgs, ANI_VERSION_1, &env); 155 if (status != ANI_OK) { 156 status = vm->GetEnv(ANI_VERSION_1, &env); 157 if (status != ANI_OK) { 158 HILOGE("vm GetEnv, err: %{public}d", status); 159 return nullptr; 160 } 161 } 162 return env; 163 } 164 DetachThreadEnv(ani_vm * vm)165 static void DetachThreadEnv(ani_vm *vm) 166 { 167 if (vm && GetThreadEnvStorage()) { 168 auto status = vm->DetachCurrentThread(); 169 if (status != ANI_OK) { 170 HILOGE("Detach thread env from vm failed! status: %{public}d", status); 171 return; 172 } 173 GetThreadEnvStorage() = nullptr; 174 } 175 } 176 SendEventToMainThread(const function<void ()> & func)177 static bool SendEventToMainThread(const function<void()> &func) 178 { 179 if (func == nullptr) { 180 HILOGE("func is nullptr!"); 181 return false; 182 } 183 184 auto &mainHandler = GetMainHandler(); 185 if (!mainHandler) { 186 HILOGE("mainHandler is not initialized!"); 187 return false; 188 } 189 bool succ = mainHandler->PostTask(func, "", 0, OHOS::AppExecFwk::EventQueue::Priority::HIGH, {}); 190 if (!succ) { 191 HILOGE("Failed to post task to main thread."); 192 return false; 193 } 194 return true; 195 } 196 197 private: GetMainHandler()198 static std::shared_ptr<OHOS::AppExecFwk::EventHandler> &GetMainHandler() 199 { 200 static std::shared_ptr<OHOS::AppExecFwk::EventHandler> mainHandler = 201 []() -> std::shared_ptr<OHOS::AppExecFwk::EventHandler> { 202 auto runner = OHOS::AppExecFwk::EventRunner::GetMainEventRunner(); 203 if (runner) { 204 return CreateSharedPtr<OHOS::AppExecFwk::EventHandler>(runner); 205 } else { 206 HILOGE("Get main event runner failed when initializing mainHandler!"); 207 return nullptr; 208 } 209 }(); 210 211 return mainHandler; 212 } 213 }; 214 215 } // namespace OHOS::FileManagement::ModuleFileIO::ANI 216 #endif // INTERFACES_KITS_JS_SRC_COMMON_ANI_HELPER_ANI_HELPER_H