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