• 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 #include <securec.h>
17 #include <chrono>
18 #include <cinttypes>
19 
20 #include "ani_utils.h"
21 #include "datashare_valuebucket_convert.h"
22 #include "ani_datashare_observer.h"
23 
24 namespace OHOS {
25 namespace DataShare {
26 using namespace std::chrono;
ANIInnerObserver(ani_vm * vm,ani_ref callback)27 ANIInnerObserver::ANIInnerObserver(ani_vm *vm, ani_ref callback) : vm_(vm), callback_(callback)
28 {
29 }
30 
~ANIInnerObserver()31 ANIInnerObserver::~ANIInnerObserver()
32 {
33     vm_->DetachCurrentThread();
34 }
35 
Convert2TSValue(ani_env * env,const std::monostate & value)36 ani_object ANIInnerObserver::Convert2TSValue(ani_env *env, const std::monostate &value)
37 {
38     (void)env;
39     (void)value;
40     return nullptr;
41 }
42 
Convert2TSValue(ani_env * env,const std::string & value)43 ani_object ANIInnerObserver::Convert2TSValue(ani_env *env, const std::string &value)
44 {
45     return StringToObject(env, value);
46 }
47 
Convert2TSValue(ani_env * env,const std::vector<uint8_t> & values)48 ani_object ANIInnerObserver::Convert2TSValue(ani_env *env, const std::vector<uint8_t> &values)
49 {
50     return Uint8ArrayToObject(env, values);
51 }
52 
Convert2TSValue(ani_env * env,int64_t value)53 ani_object ANIInnerObserver::Convert2TSValue(ani_env *env, int64_t value)
54 {
55     return DoubleToObject(env, value);
56 }
57 
Convert2TSValue(ani_env * env,double value)58 ani_object ANIInnerObserver::Convert2TSValue(ani_env *env, double value)
59 {
60     return DoubleToObject(env, value);
61 }
62 
Convert2TSValue(ani_env * env,bool value)63 ani_object ANIInnerObserver::Convert2TSValue(ani_env *env, bool value)
64 {
65     return BoolToObject(env, value);
66 }
67 
68 template<typename _VTp>
ReadVariant(ani_env * env,size_t step,size_t index,const _VTp & value)69 ani_object ANIInnerObserver::ReadVariant(ani_env *env, size_t step, size_t index, const _VTp &value)
70 {
71     return nullptr;
72 }
73 
74 template<typename _VTp, typename _First, typename ..._Rest>
ReadVariant(ani_env * env,size_t step,size_t index,const _VTp & value)75 ani_object ANIInnerObserver::ReadVariant(ani_env *env, size_t step, size_t index, const _VTp &value)
76 {
77     if (env == nullptr) {
78         LOG_ERROR("env is nullptr %{public}s", __func__);
79         return nullptr;
80     }
81     if (step == index) {
82         auto *realValue = std::get_if<_First>(&value);
83         if (realValue == nullptr) {
84             return nullptr;
85         }
86 
87         return Convert2TSValue(env, *realValue);
88     }
89 
90     return ReadVariant<_VTp, _Rest...>(env, step + 1, index, value);
91 }
92 
93 template<class... Types>
Convert2TSValue(ani_env * env,const std::variant<Types...> & value)94 ani_object ANIInnerObserver::Convert2TSValue(ani_env *env, const std::variant<Types...> &value)
95 {
96     return ReadVariant<decltype(value), Types...>(env, 0, value.index(), value);
97 }
98 
Convert2TSValue(ani_env * env,const DataShareValuesBucket & valueBucket)99 ani_object ANIInnerObserver::Convert2TSValue(ani_env *env, const DataShareValuesBucket &valueBucket)
100 {
101     ani_object valuesBucketList = nullptr;
102     static const char *className = "Lescompat/Record;";
103 
104     ani_class cls;
105     if (ANI_OK != env->FindClass(className, &cls)) {
106         LOG_ERROR("Not found '%{public}s'.", className);
107         return valuesBucketList;
108     }
109 
110     ani_method aniCtor;
111     if (ANI_OK != env->Class_FindMethod(cls, "<ctor>", ":V", &aniCtor)) {
112         LOG_ERROR("Class_GetMethod <ctor> Failed '%{public}s'.", className);
113         return valuesBucketList;
114     }
115 
116     if (ANI_OK != env->Object_New(cls, aniCtor, &valuesBucketList)) {
117         LOG_ERROR("Object_New Failed '%{public}s'.", className);
118         return valuesBucketList;
119     }
120 
121     ani_method setter;
122     if (ANI_OK != env->Class_FindMethod(cls, "$_set", nullptr, &setter)) {
123         LOG_ERROR("Class_GetMethod set Failed '%{public}s'.", className);
124         return valuesBucketList;
125     }
126 
127     const auto &valuesMap = valueBucket.valuesMap;
128     for (auto& value : valuesMap) {
129         ani_string aniKey = AniStringUtils::ToAni(env, value.first);
130         ani_object aniObjVal = Convert2TSValue(env, value.second);
131         if (ANI_OK != env->Object_CallMethod_Void(valuesBucketList, setter, aniKey, aniObjVal)) {
132             LOG_ERROR("Object_CallMethodByName_Void  $_set Faild ");
133             break;
134         }
135     }
136 
137     return valuesBucketList;
138 }
139 
140 template<typename T>
Convert2TSValue(ani_env * env,const std::vector<T> & values)141 ani_object ANIInnerObserver::Convert2TSValue(ani_env *env, const std::vector<T> &values)
142 {
143     ani_class arrayCls;
144     if (ANI_OK != env->FindClass("Lescompat/Array;", &arrayCls)) {
145         LOG_ERROR("FindClass Lescompat/Array; Failed");
146         return nullptr;
147     }
148 
149     ani_method arrayCtor;
150     if (ANI_OK != env->Class_FindMethod(arrayCls, "<ctor>", "I:V", &arrayCtor)) {
151         LOG_ERROR("Class_FindMethod <ctor> Failed");
152         return nullptr;
153     }
154 
155     ani_object arrayObj;
156     if (ANI_OK != env->Object_New(arrayCls, arrayCtor, &arrayObj, values.size())) {
157         LOG_ERROR("Object_New Array Faild");
158         return nullptr;
159     }
160 
161     ani_size index = 0;
162     for (auto value : values) {
163         if (ANI_OK != env->Object_CallMethodByName_Void(arrayObj, "$_set", "ILstd/core/Object;:V", index,
164             Convert2TSValue(env, value))) {
165             LOG_ERROR("Object_CallMethodByName_Void  $_set Faild ");
166             break;
167         }
168 
169         index++;
170     }
171 
172     return arrayObj;
173 }
174 
GetEnumItem(ani_env * env,int32_t type)175 ani_enum_item ANIInnerObserver::GetEnumItem(ani_env *env, int32_t type)
176 {
177     ani_namespace ns;
178     static const char *namespaceName = "L@ohos/data/dataShare/dataShare;";
179     if (ANI_OK != env->FindNamespace(namespaceName, &ns)) {
180         LOG_ERROR("Not found '%{public}s'", namespaceName);
181         return nullptr;
182     }
183 
184     ani_enum aniEnum{};
185     const char *enumName = "LChangeType;";
186     if (ANI_OK != env->Namespace_FindEnum(ns, enumName, &aniEnum)) {
187         LOG_ERROR("Not found '%{public}s'", enumName);
188         return nullptr;
189     }
190 
191     int32_t index = 0U;
192     ani_enum_item enumItem{};
193     while (ANI_OK == env->Enum_GetEnumItemByIndex(aniEnum, index++, &enumItem)) {
194         ani_int intValue = -1;
195         if (ANI_OK != env->EnumItem_GetValue_Int(enumItem, &intValue)) {
196             LOG_ERROR("EnumItem_GetValue_Int failed.");
197             return nullptr;
198         }
199 
200         if (intValue == type) {
201             return enumItem;
202         }
203     }
204 
205     LOG_ERROR("Get enumItem by %{public}d failed.", type);
206     return nullptr;
207 }
208 
GetNewChangeInfo(ani_env * env)209 ani_object ANIInnerObserver::GetNewChangeInfo(ani_env *env)
210 {
211     if (env == nullptr) {
212         LOG_ERROR("env is nullptr %{public}s", __func__);
213         return nullptr;
214     }
215     ani_namespace ns;
216     const char *spaceName = "L@ohos/data/dataShare/dataShare;";
217     if (ANI_OK != env->FindNamespace(spaceName, &ns)) {
218         LOG_ERROR("Not found space name '%{public}s'", spaceName);
219         return nullptr;
220     }
221 
222     ani_class cls;
223     const char *className = "LChangeInfoInner;";
224     if (ANI_OK != env->Namespace_FindClass(ns, className, &cls)) {
225         LOG_ERROR("Not found class name '%{public}s'", className);
226         return nullptr;
227     }
228 
229     ani_method ctor;
230     if (ANI_OK != env->Class_FindMethod(cls, "<ctor>", nullptr, &ctor)) {
231         LOG_ERROR("Get ctor Failed");
232         return nullptr;
233     }
234 
235     ani_object object;
236     if (ANI_OK != env->Object_New(cls, ctor, &object)) {
237         LOG_ERROR("Create GetNewChangeInfo Object Failed");
238         return nullptr;
239     }
240 
241     return object;
242 }
243 
Convert2TSValue(ani_env * env,const DataShareObserver::ChangeInfo & changeInfo)244 ani_object ANIInnerObserver::Convert2TSValue(ani_env *env, const DataShareObserver::ChangeInfo& changeInfo)
245 {
246     ani_object infoObj = GetNewChangeInfo(env);
247     if (infoObj == nullptr) {
248         LOG_ERROR("Create ts new ChangeInfo object failed!");
249         return nullptr;
250     }
251 
252     ani_enum_item aniType = GetEnumItem(env, ANIDataShareObserver::UPDATE);
253     if (aniType == nullptr) {
254         LOG_ERROR("GetEnumItem failed");
255         return nullptr;
256     }
257 
258     ani_status status = env->Object_SetPropertyByName_Ref(infoObj, "type", aniType);
259     if (ANI_OK != status) {
260         LOG_ERROR("Object_SetFieldByName_Int failed status : %{public}d", status);
261         return nullptr;
262     }
263 
264     ani_string uri;
265     env->String_NewUTF8(changeInfo.uris_.front().ToString().c_str(), changeInfo.uris_.front().ToString().size(), &uri);
266     status = env->Object_SetPropertyByName_Ref(infoObj, "uri", uri);
267     if (ANI_OK != status) {
268         LOG_ERROR("Object_SetPropertyByName_Ref failed status : %{public}d", status);
269         return nullptr;
270     }
271 
272     auto &valBucket = const_cast<DataShareObserver::ChangeInfo &>(changeInfo);
273     std::vector<DataShareValuesBucket> VBuckets = ValueProxy::Convert(std::move(valBucket.valueBuckets_));
274     ani_object valueBuckets = Convert2TSValue(env, VBuckets);
275     status = env->Object_SetPropertyByName_Ref(infoObj, "values", valueBuckets);
276     if (ANI_OK != status) {
277         LOG_ERROR("Object_SetPropertyByName_Ref failed status : %{public}d", status);
278         return nullptr;
279     }
280 
281     return infoObj;
282 }
283 
OnChange(const DataShareObserver::ChangeInfo & changeInfo,bool isNotifyDetails)284 void ANIInnerObserver::OnChange(const DataShareObserver::ChangeInfo& changeInfo, bool isNotifyDetails)
285 {
286     auto time = static_cast<uint64_t>(duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count());
287     LOG_INFO("ANIInnerObserver datashare callback start, times %{public}" PRIu64 ".", time);
288     if (callback_ == nullptr) {
289         LOG_ERROR("callback_ is nullptr");
290         return;
291     }
292 
293     ani_env *env = nullptr;
294     ani_options aniArgs {0, nullptr};
295     if (ANI_ERROR == vm_->AttachCurrentThread(&aniArgs, ANI_VERSION_1, &env)) {
296         if (ANI_OK != vm_->GetEnv(ANI_VERSION_1, &env)) {
297             LOG_ERROR("GetEnv failed");
298             return;
299         }
300     }
301 
302     ani_ref result;
303     auto fnObj = reinterpret_cast<ani_fn_object>(callback_);
304     if (fnObj == nullptr) {
305         LOG_ERROR("%{public}s: fnObj == nullptr", __func__);
306         return;
307     }
308 
309     std::vector<ani_ref> args = { nullptr };
310     if (isNotifyDetails) {
311         auto argsObj = Convert2TSValue(env, changeInfo);
312         if (argsObj == nullptr) {
313             LOG_ERROR("%{public}s: argsObj is null", __func__);
314             return;
315         }
316 
317         args.push_back(argsObj);
318     }
319 
320     ani_status callStatus = env->FunctionalObject_Call(fnObj, args.size(), args.data(), &result);
321     if (ANI_OK != callStatus) {
322         LOG_ERROR("ani_call_function failed status : %{public}d", callStatus);
323         return;
324     }
325 
326     LOG_INFO("ANIInnerObserver datashare callback end, times %{public}" PRIu64 ".", time);
327 }
328 
GetCallback()329 ani_ref ANIInnerObserver::GetCallback()
330 {
331     return callback_;
332 }
333 }  // namespace DataShare
334 }  // namespace OHOS