• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 ANI_UTILS_H
17 #define ANI_UTILS_H
18 
19 #include <ani.h>
20 
21 #include <cstdarg>
22 #include <iostream>
23 #include <memory>
24 #include <optional>
25 #include <string>
26 #include <vector>
27 #include "log.h"
28 #include "base.h"
29 
30 namespace OHOS {
31 namespace AniUtil {
32 
33 class AniObjectUtils {
34 public:
Create(ani_env * env,const char * nsName,const char * clsName,...)35     static ani_object Create(ani_env *env, const char* nsName, const char* clsName, ...)
36     {
37         ani_namespace ns;
38         if (ANI_OK != env->FindNamespace(nsName, &ns)) {
39             REQUEST_HILOGE("[ANI] Not found namespace %{public}s", nsName);
40             return nullptr;
41         }
42 
43         ani_class cls;
44         if (ANI_OK != env->Namespace_FindClass(ns, clsName, &cls)) {
45             REQUEST_HILOGE("[ANI] Not found namespace %{public}s", clsName);
46             return nullptr;
47         }
48 
49         ani_object obj;
50         va_list args;
51         va_start(args, clsName);
52         obj = CreateV(env, cls, args);
53         va_end(args);
54         return obj;
55     }
56 
Create(ani_env * env,const char * nsName,const char * subNsName,const char * clsName,...)57     static ani_object Create(ani_env *env, const char* nsName, const char* subNsName, const char* clsName, ...)
58     {
59         ani_namespace ns;
60         if (ANI_OK != env->FindNamespace(nsName, &ns)) {
61             REQUEST_HILOGE("[ANI] Not found namespace %{public}s", nsName);
62             return nullptr;
63         }
64 
65         ani_namespace subNs;
66         if (ANI_OK != env->Namespace_FindNamespace(ns, subNsName, &subNs)) {
67             REQUEST_HILOGE("[ANI] Not found namespace %{public}s", subNsName);
68             return nullptr;
69         }
70 
71         ani_class cls;
72         if (ANI_OK != env->Namespace_FindClass(subNs, clsName, &cls)) {
73             REQUEST_HILOGE("[ANI] Not found class %{public}s", clsName);
74             return nullptr;
75         }
76 
77         ani_object obj;
78         va_list args;
79         va_start(args, clsName);
80         obj = CreateV(env, cls, args);
81         va_end(args);
82         return obj;
83     }
84 
Create(ani_env * env,const char * clsName,...)85     static ani_object Create(ani_env *env, const char* clsName, ...)
86     {
87         ani_class cls;
88         if (ANI_OK != env->FindClass(clsName, &cls)) {
89             REQUEST_HILOGE("[ANI] Not found class %{public}s", clsName);
90             return nullptr;
91         }
92 
93         ani_object obj;
94         va_list args;
95         va_start(args, clsName);
96         obj = CreateV(env, cls, args);
97         va_end(args);
98         return obj;
99     }
100 
Create(ani_env * env,ani_class cls,...)101     static ani_object Create(ani_env *env, ani_class cls, ...)
102     {
103         ani_method ctor;
104         if (ANI_OK != env->Class_FindMethod(cls, "<ctor>", nullptr, &ctor)) {
105             REQUEST_HILOGE("[ANI] Not found <ctor> for class");
106             return nullptr;
107         }
108 
109         ani_object obj;
110         va_list args;
111         va_start(args, cls);
112         obj = CreateV(env, cls, args);
113         va_end(args);
114         return obj;
115     }
116 
From(ani_env * env,bool value)117     static ani_object From(ani_env *env, bool value)
118     {
119         return Create(env, "Lstd/core/Boolean;", static_cast<ani_boolean>(value));
120     }
121 
122     template<typename T>
123     static ani_status Wrap(ani_env *env, ani_object object, T* nativePtr, const char* propName = "nativePtr")
124     {
125         return env->Object_SetFieldByName_Long(object, propName, reinterpret_cast<ani_long>(nativePtr));
126     }
127 
128     template<typename T>
129     static T* Unwrap(ani_env *env, ani_object object, const char* propName = "nativePtr")
130     {
131         ani_long nativePtr;
132         if (ANI_OK != env->Object_GetFieldByName_Long(object, propName, &nativePtr)) {
133             return nullptr;
134         }
135         return reinterpret_cast<T*>(nativePtr);
136     }
137 
138 private:
CreateV(ani_env * env,ani_class cls,va_list args)139     static ani_object CreateV(ani_env *env, ani_class cls, va_list args)
140     {
141         ani_method ctor;
142         if (ANI_OK != env->Class_FindMethod(cls, "<ctor>", nullptr, &ctor)) {
143             REQUEST_HILOGE("[ANI] Not found <ctor> for class");
144             return nullptr;
145         }
146 
147         ani_object obj;
148         ani_status status = env->Object_New_V(cls, ctor, &obj, args);
149         if (ANI_OK != status) {
150             REQUEST_HILOGE("[ANI] Failed to Object_New for class.");
151             return nullptr;
152         }
153         return obj;
154     }
155 };
156 
157 
158 class AniStringUtils {
159 public:
ToStd(ani_env * env,ani_string ani_str)160     static std::string ToStd(ani_env *env, ani_string ani_str)
161     {
162         ani_size strSize;
163         env->String_GetUTF8Size(ani_str, &strSize);
164 
165         std::vector<char> buffer(strSize + 1); // +1 for null terminator
166         char* utf8_buffer = buffer.data();
167 
168         //String_GetUTF8 Supportted by https://gitee.com/openharmony/arkcompiler_runtime_core/pulls/3416
169         ani_size bytes_written = 0;
170         env->String_GetUTF8(ani_str, utf8_buffer, strSize + 1, &bytes_written);
171 
172         utf8_buffer[bytes_written] = '\0';
173         std::string content = std::string(utf8_buffer);
174         return content;
175     }
176 
ToAni(ani_env * env,const std::string & str)177     static ani_string ToAni(ani_env* env, const std::string& str)
178     {
179         ani_string aniStr = nullptr;
180         if (ANI_OK != env->String_NewUTF8(str.data(), str.size(), &aniStr)) {
181             REQUEST_HILOGE("[ANI] Unsupported ANI_VERSION_1");
182             return nullptr;
183         }
184         return aniStr;
185     }
186 };
187 
188 
189 class UnionAccessor {
190 public:
UnionAccessor(ani_env * env,ani_object obj)191     UnionAccessor(ani_env *env, ani_object obj) : env_(env), obj_(obj)
192     {
193     }
194 
IsInstanceOf(const std::string & cls_name)195     bool IsInstanceOf(const std::string& cls_name)
196     {
197         ani_class cls;
198         env_->FindClass(cls_name.c_str(), &cls);
199 
200         ani_boolean ret;
201         env_->Object_InstanceOf(obj_, cls, &ret);
202         return ret;
203     }
204 
205     template<typename T>
206     bool IsInstanceOfType();
207 
208     template<typename T>
Convert()209     expected<T, ani_status> Convert()
210     {
211         T value{};
212         bool status = TryConvert<T>(value);
213         if (ANI_OK != status) {
214             return ANI_ERROR;
215         }
216         return value;
217     }
218 
219     template<typename T>
220     bool TryConvert(T &value);
221 
222     template<typename T>
223     bool TryConvertArray(std::vector<T> &value);
224 
225 private:
226     ani_env *env_;
227     ani_object obj_;
228 };
229 
230 template<>
231 inline bool UnionAccessor::IsInstanceOfType<bool>()
232 {
233     return IsInstanceOf("Lstd/core/Boolean;");
234 }
235 
236 template<>
237 inline bool UnionAccessor::IsInstanceOfType<int>()
238 {
239     return IsInstanceOf("Lstd/core/Int;");
240 }
241 
242 template<>
243 inline bool UnionAccessor::IsInstanceOfType<double>()
244 {
245     return IsInstanceOf("Lstd/core/Double;");
246 }
247 
248 template<>
249 inline bool UnionAccessor::IsInstanceOfType<std::string>()
250 {
251     return IsInstanceOf("Lstd/core/String;");
252 }
253 
254 template<>
255 inline bool UnionAccessor::TryConvert<bool>(bool &value)
256 {
257     if (!IsInstanceOfType<bool>()) {
258         return false;
259     }
260 
261     ani_boolean aniValue;
262     auto ret = env_->Object_CallMethodByName_Boolean(obj_, "unboxed", nullptr, &aniValue);
263     if (ret != ANI_OK) {
264         return false;
265     }
266     value = static_cast<bool>(aniValue);
267     return true;
268 }
269 
270 template<>
271 inline bool UnionAccessor::TryConvert<int>(int &value)
272 {
273     if (!IsInstanceOfType<int>()) {
274         return false;
275     }
276 
277     ani_int aniValue;
278     auto ret = env_->Object_CallMethodByName_Int(obj_, "unboxed", nullptr, &aniValue);
279     if (ret != ANI_OK) {
280         return false;
281     }
282     value = static_cast<int>(aniValue);
283     return true;
284 }
285 
286 template<>
287 inline bool UnionAccessor::TryConvert<double>(double &value)
288 {
289     if (!IsInstanceOfType<double>()) {
290         return false;
291     }
292 
293     ani_double aniValue;
294     auto ret = env_->Object_CallMethodByName_Double(obj_, "unboxed", nullptr, &aniValue);
295     if (ret != ANI_OK) {
296         return false;
297     }
298     value = static_cast<double>(aniValue);
299     return true;
300 }
301 
302 template<>
303 inline bool UnionAccessor::TryConvert<std::string>(std::string &value)
304 {
305     if (!IsInstanceOfType<std::string>()) {
306         return false;
307     }
308 
309     value = AniStringUtils::ToStd(env_, static_cast<ani_string>(obj_));
310     return true;
311 }
312 
313 ani_boolean IsInstanceOf(ani_env *env, const std::string &cls_name, ani_object obj);
314 
315 class OptionalAccessor {
316 public:
OptionalAccessor(ani_env * env,ani_object obj)317     OptionalAccessor(ani_env *env, ani_object obj) : env_(env), obj_(obj)
318     {
319     }
320 
IsUndefined()321     bool IsUndefined()
322     {
323         ani_boolean isUndefined;
324         env_->Reference_IsUndefined(obj_, &isUndefined);
325         return isUndefined;
326     }
327 
328     template<typename T>
329     expected<T, ani_status> Convert();
330 
331 private:
ConvertToString()332     expected<std::string, ani_status> ConvertToString()
333     {
334         if (IsUndefined()) {
335             return ANI_ERROR;
336         }
337 
338         ani_size strSize;
339         env_->String_GetUTF8Size(static_cast<ani_string>(obj_), &strSize);
340 
341         std::vector<char> buffer(strSize + 1);
342         char* utf8_buffer = buffer.data();
343 
344         ani_size bytes_written = 0;
345         env_->String_GetUTF8(static_cast<ani_string>(obj_), utf8_buffer, strSize + 1, &bytes_written);
346 
347         utf8_buffer[bytes_written] = '\0';
348         std::string content = std::string(utf8_buffer);
349         return content;
350     }
351 
352 private:
353     ani_env *env_;
354     ani_object obj_;
355 };
356 
357 template<>
358 inline expected<bool, ani_status> OptionalAccessor::Convert<bool>()
359 {
360     if (IsUndefined()) {
361         return ANI_ERROR;
362     }
363 
364     ani_boolean aniValue;
365     auto ret = env_->Object_CallMethodByName_Boolean(obj_, "unboxed", nullptr, &aniValue);
366     if (ret != ANI_OK) {
367         return ret;
368     }
369     auto value = static_cast<bool>(aniValue);
370     return value;
371 }
372 
373 template<>
374 inline expected<double, ani_status> OptionalAccessor::Convert<double>()
375 {
376     if (IsUndefined()) {
377         return ANI_ERROR;
378     }
379 
380     ani_double aniValue;
381     auto ret = env_->Object_CallMethodByName_Double(obj_, "doubleValue", nullptr, &aniValue);
382     if (ret != ANI_OK) {
383         return ret;
384     }
385     auto value = static_cast<double>(aniValue);
386     return value;
387 }
388 
389 template<>
390 inline expected<std::string, ani_status> OptionalAccessor::Convert<std::string>()
391 {
392     return ConvertToString();
393 }
394 
395 
396 class EnumAccessor {
397 public:
EnumAccessor(ani_env * env,const char * className,ani_int index)398     EnumAccessor(ani_env *env, const char* className, ani_int index) : env_(env)
399     {
400         initStatus_ = ANI_ERROR;
401         ani_enum_item item;
402         initStatus_ = GetItem(className, index, item);
403         if (ANI_OK == initStatus_) {
404             item_ = item;
405         }
406     }
407 
EnumAccessor(ani_env * env,ani_enum_item item)408     EnumAccessor(ani_env *env, ani_enum_item item) : env_(env), item_(item)
409     {
410         initStatus_ = ANI_ERROR;
411     }
412 
413     template<typename T>
To()414     expected<T, ani_status> To()
415     {
416         int32_t value{};
417         ani_status status = ToInt(value);
418         if (ANI_OK != status) {
419             return status;
420         }
421         return static_cast<T>(value);
422     }
423 
ToInt(int32_t & value)424     ani_status ToInt(int32_t &value)
425     {
426         if (!item_) {
427             return initStatus_;
428         }
429 
430         ani_status status = env_->EnumItem_GetValue_Int(item_.value(), &value);
431         if (ANI_OK != status) {
432             REQUEST_HILOGE("Failed to call EnumItem_GetValue_Int");
433             return status;
434         }
435         return ANI_OK;
436     }
437 
ToInt()438     expected<int32_t, ani_status> ToInt()
439     {
440         int32_t value;
441         ani_status status = ToInt(value);
442         if (ANI_OK != status) {
443             return status;
444         }
445         return value;
446     }
447 
ToString(std::string & value)448     ani_status ToString(std::string &value)
449     {
450         if (!item_) {
451             return initStatus_;
452         }
453 
454         ani_string strValue;
455         ani_status status = env_->EnumItem_GetValue_String(item_.value(), &strValue);
456         if (ANI_OK != status) {
457             REQUEST_HILOGE("Failed to call EnumItem_GetValue_String");
458             return status;
459         }
460         value = AniStringUtils::ToStd(env_, strValue);
461         return ANI_OK;
462     }
463 
ToString()464     expected<std::string, ani_status> ToString()
465     {
466         std::string value;
467         ani_status status = ToString(value);
468         if (ANI_OK != status) {
469             return status;
470         }
471         return value;
472     }
473 
474 private:
GetItem(const char * className,ani_int index,ani_enum_item & item)475     ani_status GetItem(const char* className, ani_int index, ani_enum_item &item)
476     {
477         ani_status status = ANI_ERROR;
478         ani_enum enumType;
479         status = env_->FindEnum(className, &enumType);
480         if (ANI_OK != status) {
481             REQUEST_HILOGE("Failed to call FindEnum for %{public}s", className);
482             return status;
483         }
484 
485         status = env_->Enum_GetEnumItemByIndex(enumType, index, &item);
486         if (ANI_OK != status) {
487             REQUEST_HILOGE("Failed to call Enum_GetEnumItemByIndex for %{public}s, [%{public}d]", className, index);
488             return status;
489         }
490         return ANI_OK;
491     }
492 
493 private:
494     ani_env *env_;
495     std::optional<ani_enum_item> item_;
496     ani_status initStatus_;
497 };
498 
499 
500 class ArrayAccessor {
501 public:
ArrayAccessor(ani_env * env,ani_object obj)502     ArrayAccessor(ani_env *env, ani_object obj) : env_(env), obj_(obj)
503     {
504     }
505 
Length(std::size_t & length)506     ani_status Length(std::size_t &length)
507     {
508         ani_double value;
509         if (ANI_OK != env_->Object_GetPropertyByName_Double(obj_, "length", &value)) {
510             return ANI_ERROR;
511         }
512         length = static_cast<std::size_t>(value);
513         return ANI_OK;
514     }
515 
516     template <typename OutputIterator, typename TransformFunc>
Transform(OutputIterator out,TransformFunc && transform)517     ani_status Transform(OutputIterator out, TransformFunc&& transform)
518     {
519         ani_status status = ANI_ERROR;
520         std::size_t length = 0;
521         status = Length(length);
522         if (ANI_OK != status) {
523             return status;
524         }
525         for (std::size_t i = 0; i < length; i++) {
526             ani_ref itemRef;
527             status = env_->Object_CallMethodByName_Ref(obj_, "$_get", "I:Lstd/core/Object;", &itemRef, (ani_int)i);
528             if (ANI_OK != status) {
529                 return status;
530             }
531             typename OutputIterator::container_type::value_type value;
532             status = transform(env_, itemRef, value);
533             if (ANI_OK != status) {
534                 return status;
535             }
536             *out++ = value;
537         }
538         return ANI_OK;
539     }
540 
541 private:
542     ani_env *env_ = nullptr;
543     ani_object obj_ = nullptr;
544 };
545 
546 struct ToDouble {
operatorToDouble547     ani_status operator()(ani_env *env, ani_ref &itemRef, double &value) const
548     {
549         ani_double aniValue;
550         ani_object itemObj = static_cast<ani_object>(itemRef);
551         ani_status status = env->Object_CallMethodByName_Double(itemObj, "unboxed", nullptr, &aniValue);
552         if (ANI_OK != status) {
553             value = static_cast<double>(aniValue);
554         }
555         return status;
556     }
557 };
558 
559 
560 class AniLocalScopeGuard {
561 public:
AniLocalScopeGuard(ani_env * env,size_t nrRefs)562     AniLocalScopeGuard(ani_env *env, size_t nrRefs) : env_(env)
563     {
564         status_ = env_->CreateLocalScope(nrRefs);
565     }
566 
~AniLocalScopeGuard()567     ~AniLocalScopeGuard()
568     {
569         if (ANI_OK != status_) {
570             return;
571         }
572         env_->DestroyLocalScope();
573     }
574 
IsStatusOK()575     bool IsStatusOK()
576     {
577         return ANI_OK == status_;
578     }
579 
GetStatus()580     ani_status GetStatus()
581     {
582         return status_;
583     }
584 
585 private:
586     ani_env *env_ = nullptr;
587     ani_status status_ = ANI_ERROR;
588 };
589 
590 } // namespace AniUtil
591 } // namespace OHOS
592 
593 #endif
594