1 /*
2  * Copyright (c) 2022 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 "js_datashare_ext_ability.h"
17 
18 #include "ability_info.h"
19 #include "dataobs_mgr_client.h"
20 #include "datashare_log.h"
21 #include "datashare_predicates_proxy.h"
22 #include "datashare_stub_impl.h"
23 #include "ikvstore_data_service.h"
24 #include "idata_share_service.h"
25 #include "iservice_registry.h"
26 #include "js_datashare_ext_ability_context.h"
27 #include "js_proxy.h"
28 #include "js_runtime.h"
29 #include "js_runtime_utils.h"
30 #include "napi_common_util.h"
31 #include "napi_common_want.h"
32 #include "napi_datashare_values_bucket.h"
33 #include "napi_remote_object.h"
34 #include "system_ability_definition.h"
35 
36 using namespace OHOS::DistributedShare::DataShare;
37 
38 namespace OHOS {
39 namespace DataShare {
40 using namespace AbilityRuntime;
41 namespace {
42 constexpr int INVALID_VALUE = -1;
43 static constexpr int32_t MAX_ARGC = 6;
44 static constexpr int32_t MIN_ARGC = 2;
45 constexpr const char ASYNC_CALLBACK_NAME[] = "AsyncCallback";
46 constexpr int CALLBACK_LENGTH = sizeof(ASYNC_CALLBACK_NAME) - 1;
47 }
48 
49 bool MakeNapiColumn(napi_env env, napi_value &napiColumns, const std::vector<std::string> &columns);
50 
51 using namespace OHOS::AppExecFwk;
52 using DataObsMgrClient = OHOS::AAFwk::DataObsMgrClient;
53 
Create(const std::unique_ptr<Runtime> & runtime)54 JsDataShareExtAbility* JsDataShareExtAbility::Create(const std::unique_ptr<Runtime>& runtime)
55 {
56     return new JsDataShareExtAbility(static_cast<JsRuntime&>(*runtime));
57 }
58 
JsDataShareExtAbility(JsRuntime & jsRuntime)59 JsDataShareExtAbility::JsDataShareExtAbility(JsRuntime& jsRuntime) : jsRuntime_(jsRuntime) {}
60 
~JsDataShareExtAbility()61 JsDataShareExtAbility::~JsDataShareExtAbility()
62 {
63     LOG_DEBUG("Js datashare extension destructor.");
64     jsRuntime_.FreeNativeReference(std::move(jsObj_));
65 }
66 
Init(const std::shared_ptr<AbilityLocalRecord> & record,const std::shared_ptr<OHOSApplication> & application,std::shared_ptr<AbilityHandler> & handler,const sptr<IRemoteObject> & token)67 void JsDataShareExtAbility::Init(const std::shared_ptr<AbilityLocalRecord> &record,
68     const std::shared_ptr<OHOSApplication> &application, std::shared_ptr<AbilityHandler> &handler,
69     const sptr<IRemoteObject> &token)
70 {
71     DataShareExtAbility::Init(record, application, handler, token);
72     std::string srcPath = "";
73     GetSrcPath(srcPath);
74     if (srcPath.empty()) {
75         LOG_ERROR("Failed to get srcPath");
76         return;
77     }
78 
79     std::string moduleName(Extension::abilityInfo_->moduleName);
80     moduleName.append("::").append(abilityInfo_->name);
81     LOG_DEBUG("module:%{public}s, srcPath:%{public}s.", moduleName.c_str(), srcPath.c_str());
82     HandleScope handleScope(jsRuntime_);
83     napi_env env = jsRuntime_.GetNapiEnv();
84 
85     jsObj_ = jsRuntime_.LoadModule(
86         moduleName, srcPath, abilityInfo_->hapPath, abilityInfo_->compileMode == CompileMode::ES_MODULE);
87     if (jsObj_ == nullptr) {
88         LOG_ERROR("Failed to get jsObj_, moduleName:%{public}s.", moduleName.c_str());
89         return;
90     }
91     napi_value obj = jsObj_->GetNapiValue();
92     if (obj == nullptr) {
93         LOG_ERROR("Failed to get JsDataShareExtAbility object, moduleName:%{public}s.", moduleName.c_str());
94         return;
95     }
96 
97     auto context = GetContext();
98     if (context == nullptr) {
99         LOG_ERROR("Failed to get context, moduleName:%{public}s.", moduleName.c_str());
100         return;
101     }
102     napi_value contextObj = CreateJsDataShareExtAbilityContext(env, context);
103     auto contextRef = jsRuntime_.LoadSystemModule("application.DataShareExtensionAbilityContext", &contextObj, 1);
104     if (contextRef == nullptr) {
105         LOG_ERROR("Failed to get contextRef");
106         return;
107     }
108     contextObj = contextRef->GetNapiValue();
109     context->Bind(jsRuntime_, contextRef.release());
110     napi_set_named_property(env, obj, "context", contextObj);
111     napi_wrap(env, contextObj, new std::weak_ptr<AbilityRuntime::Context>(context),
112         [](napi_env, void *data, void *) {
113             LOG_INFO("Finalizer for weak_ptr datashare extension ability context is called");
114             delete static_cast<std::weak_ptr<AbilityRuntime::Context>*>(data);
115         }, nullptr, nullptr);
116 }
117 
OnStart(const AAFwk::Want & want)118 void JsDataShareExtAbility::OnStart(const AAFwk::Want &want)
119 {
120     Extension::OnStart(want);
121     HandleScope handleScope(jsRuntime_);
122     napi_env env = jsRuntime_.GetNapiEnv();
123     napi_handle_scope scope = nullptr;
124     napi_open_handle_scope(env, &scope);
125     if (scope == nullptr) {
126         return;
127     }
128     napi_value napiWant = OHOS::AppExecFwk::WrapWant(env, want);
129     napi_value argv[] = {napiWant};
130     std::shared_ptr<AsyncContext> context = std::make_shared<AsyncContext>();
131     context->isNeedNotify_ = true;
132     CallObjectMethod("onCreate", argv, sizeof(argv)/sizeof(argv[0]), context);
133     napi_close_handle_scope(env, scope);
134 }
135 
OnConnect(const AAFwk::Want & want)136 sptr<IRemoteObject> JsDataShareExtAbility::OnConnect(const AAFwk::Want &want)
137 {
138     Extension::OnConnect(want);
139     sptr<DataShareStubImpl> remoteObject = new (std::nothrow) DataShareStubImpl(
140         std::static_pointer_cast<JsDataShareExtAbility>(shared_from_this()),
141         jsRuntime_.GetNapiEnv());
142     if (remoteObject == nullptr) {
143         LOG_ERROR("No memory allocated for DataShareStubImpl");
144         return nullptr;
145     }
146     return remoteObject->AsObject();
147 }
148 
UnwrapBatchUpdateResult(napi_env env,napi_value & info,std::vector<BatchUpdateResult> & results)149 bool JsDataShareExtAbility::UnwrapBatchUpdateResult(napi_env env, napi_value &info,
150     std::vector<BatchUpdateResult> &results)
151 {
152     napi_value keys = 0;
153     if (napi_get_property_names(env, info, &keys) != napi_ok) {
154         LOG_ERROR("napi_get_property_names failed");
155         return false;
156     }
157 
158     uint32_t arrLen = 0;
159     if (napi_get_array_length(env, keys, &arrLen) != napi_ok) {
160         LOG_ERROR("napi_get_array_length failed");
161         return false;
162     }
163     for (size_t i = 0; i < arrLen; i++) {
164         napi_value key = 0;
165         if (napi_get_element(env, keys, i, &key) != napi_ok) {
166             LOG_ERROR("napi_get_element failed");
167             return false;
168         }
169         BatchUpdateResult batchUpdateResult;
170         batchUpdateResult.uri = DataShareJSUtils::UnwrapStringFromJS(env, key);
171         napi_value value = 0;
172         if (napi_get_property(env, info, key, &value) != napi_ok) {
173             LOG_ERROR("napi_get_property failed");
174             return false;
175         }
176         if (!UnwrapArrayInt32FromJS(env, value, batchUpdateResult.codes)) {
177             LOG_ERROR("UnwrapArrayInt32FromJS failed");
178             return false;
179         }
180         results.push_back(std::move(batchUpdateResult));
181     }
182     return true;
183 }
184 
CheckAndSetAsyncResult(napi_env env)185 void JsDataShareExtAbility::CheckAndSetAsyncResult(napi_env env)
186 {
187     napi_valuetype type = napi_undefined;
188     auto result = GetAsyncResult();
189     napi_typeof(env, result, &type);
190     if (type == napi_valuetype::napi_number) {
191         int32_t value = OHOS::AppExecFwk::UnwrapInt32FromJS(env, result);
192         SetResult(value);
193     } else if (type == napi_valuetype::napi_string) {
194         std::string value = OHOS::AppExecFwk::UnwrapStringFromJS(env, result);
195         SetResult(value);
196     } else if (type == napi_valuetype::napi_object) {
197         JSProxy::JSCreator<ResultSetBridge> *proxy = nullptr;
198         napi_unwrap(env, result, reinterpret_cast<void **>(&proxy));
199         if (proxy == nullptr) {
200             std::vector<BatchUpdateResult> results;
201             if (UnwrapBatchUpdateResult(env, result, results)) {
202                 SetResult(results);
203                 return;
204             }
205             std::vector<std::string> value;
206             OHOS::AppExecFwk::UnwrapArrayStringFromJS(env, result, value);
207             SetResult(value);
208         } else {
209             std::shared_ptr<ResultSetBridge> value = proxy->Create();
210             std::shared_ptr<DataShareResultSet> resultSet = std::make_shared<DataShareResultSet>(value);
211             SetResultSet(resultSet);
212         }
213     } else {
214         callbackResultNumber_ = -1;
215         callbackResultString_ = "";
216         callbackResultStringArr_ = {};
217         SetResultSet(nullptr);
218     }
219 }
220 
AsyncCallback(napi_env env,napi_callback_info info)221 napi_value JsDataShareExtAbility::AsyncCallback(napi_env env, napi_callback_info info)
222 {
223     if (env == nullptr || info == nullptr) {
224         LOG_ERROR("invalid param.");
225         return nullptr;
226     }
227     napi_value self = nullptr;
228     size_t argc = MAX_ARGC;
229     napi_value argv[MAX_ARGC] = { nullptr };
230     void* data = nullptr;
231     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &self, &data));
232     if (argc < MIN_ARGC || argv[0] == nullptr || argv[1] == nullptr) {
233         LOG_ERROR("invalid args, argc : %{public}zu.", argc);
234         return CreateJsUndefined(env);
235     }
236     if (data == nullptr) {
237         LOG_ERROR("invalid object.");
238         return CreateJsUndefined(env);
239     }
240 
241     AsyncCallBackPoint* point = static_cast<AsyncCallBackPoint*>(data);
242     auto instance = point->extAbility.lock();
243     if (!instance) {
244         LOG_ERROR("extension ability has been destroyed.");
245         return CreateJsUndefined(env);
246     }
247     DatashareBusinessError businessError;
248     napi_valuetype type = napi_undefined;
249     napi_typeof(env, argv[0], &type);
250     if (type == napi_valuetype::napi_object) {
251         LOG_INFO("Error in callback");
252         UnWrapBusinessError(env, argv[0], businessError);
253     }
254     if (instance != nullptr) {
255         instance->SetBusinessError(businessError);
256         instance->SetAsyncResult(argv[1]);
257         instance->CheckAndSetAsyncResult(env);
258         instance->SetRecvReply(true);
259     }
260     return CreateJsUndefined(env);
261 }
262 
AsyncCallbackWithContext(napi_env env,napi_callback_info info)263 napi_value JsDataShareExtAbility::AsyncCallbackWithContext(napi_env env, napi_callback_info info)
264 {
265     if (env == nullptr || info == nullptr) {
266         LOG_ERROR("invalid param.");
267         return nullptr;
268     }
269 
270     void* data = nullptr;
271     napi_get_cb_info(env, info, nullptr, nullptr, nullptr, &data);
272     if (data == nullptr) {
273         LOG_ERROR("invalid object.");
274         return CreateJsUndefined(env);
275     }
276 
277     AsyncPoint* instance = static_cast<AsyncPoint*>(data);
278     if (instance != nullptr) {
279         if (instance->context->isNeedNotify_) {
280             NotifyToDataShareService();
281         }
282     }
283     return CreateJsUndefined(env);
284 }
285 
CallObjectMethod(const char * name,napi_value const * argv,size_t argc,std::shared_ptr<AsyncContext> asyncContext)286 napi_value JsDataShareExtAbility::CallObjectMethod(
287     const char *name, napi_value const *argv, size_t argc, std::shared_ptr<AsyncContext> asyncContext)
288 {
289     if (!jsObj_) {
290         LOG_WARN("Not found DataShareExtAbility.js");
291         return nullptr;
292     }
293 
294     HandleEscape handleEscape(jsRuntime_);
295     napi_env env = jsRuntime_.GetNapiEnv();
296     napi_value obj = jsObj_->GetNapiValue();
297     if (obj == nullptr) {
298         LOG_ERROR("Failed to get DataShareExtAbility object");
299         return nullptr;
300     }
301 
302     napi_value method = nullptr;
303     napi_get_named_property(env, obj, name, &method);
304     if (method == nullptr) {
305         LOG_ERROR("Failed to get '%{public}s' from DataShareExtAbility object", name);
306         return nullptr;
307     }
308 
309     AsyncPoint *point = new (std::nothrow)AsyncPoint();
310     if (point == nullptr) {
311         LOG_ERROR("JsDataShareExtAbility::CallObjectMethod new AsyncPoint error.");
312         return nullptr;
313     }
314     point->context = asyncContext;
315     size_t count = argc + 1;
316     napi_value *args = new (std::nothrow) napi_value [count];
317     if (args == nullptr) {
318         LOG_ERROR("JsDataShareExtAbility::CallObjectMethod new NapiValue error.");
319         delete point;
320         return nullptr;
321     }
322     for (size_t i = 0; i < argc; i++) {
323         args[i] = argv[i];
324     }
325 
326     napi_create_function(env, ASYNC_CALLBACK_NAME, CALLBACK_LENGTH,
327         JsDataShareExtAbility::AsyncCallbackWithContext, point, &args[argc]);
328     napi_value callResult = nullptr;
329     napi_call_function(env, obj, method, count, args, &callResult);
330     auto result = handleEscape.Escape(callResult);
331     napi_add_finalizer(env, args[argc], point,
332         [](napi_env env, void* point, void* finalize_hint) {
333             delete static_cast<AsyncPoint *>(point);
334             }, nullptr, nullptr);
335     delete []args;
336     return result;
337 }
338 
CallObjectMethod(const char * name,napi_value const * argv,size_t argc,bool isAsync)339 napi_value JsDataShareExtAbility::CallObjectMethod(const char* name, napi_value const *argv,
340     size_t argc, bool isAsync)
341 {
342     if (!jsObj_) {
343         LOG_WARN("Not found DataShareExtAbility.js");
344         return nullptr;
345     }
346 
347     HandleEscape handleEscape(jsRuntime_);
348     napi_env env = jsRuntime_.GetNapiEnv();
349     napi_value obj = jsObj_->GetNapiValue();
350     if (obj == nullptr) {
351         LOG_ERROR("Failed to get DataShareExtAbility object");
352         return nullptr;
353     }
354 
355     napi_value method = nullptr;
356     napi_get_named_property(env, obj, name, &method);
357     if (method == nullptr) {
358         LOG_ERROR("Failed to get '%{public}s' from DataShareExtAbility object", name);
359         return nullptr;
360     }
361 
362     size_t count = argc + 1;
363     napi_value *args = new (std::nothrow) napi_value[count];
364     if (args == nullptr) {
365         LOG_ERROR("JsDataShareExtAbility::CallObjectMethod new napivalue error.");
366         return nullptr;
367     }
368     for (size_t i = 0; i < argc; i++) {
369         args[i] = argv[i];
370     }
371 
372     if (isAsync) {
373         auto ret = InitAsyncCallParams(argc, env, args);
374         if (ret != E_OK) {
375             LOG_ERROR("Failed to InitAsyncCallParams in isAsync.");
376             delete [] args;
377             return nullptr;
378         }
379     } else {
380         args[argc] = nullptr;
381     }
382 
383     napi_value remoteNapi = nullptr;
384     NAPI_CallingInfo oldCallingInfo;
385     NAPI_RemoteObject_saveOldCallingInfo(env, oldCallingInfo);
386     SaveNewCallingInfo(env);
387     napi_status status = napi_call_function(env, obj, method, count, args, &remoteNapi);
388     NAPI_RemoteObject_resetOldCallingInfo(env, oldCallingInfo);
389     delete []args;
390     if (status != napi_ok) {
391         return nullptr;
392     }
393     return handleEscape.Escape(remoteNapi);
394 }
395 
SaveNewCallingInfo(napi_env & env)396 void JsDataShareExtAbility::SaveNewCallingInfo(napi_env &env)
397 {
398     auto newCallingInfo = GetCallingInfo();
399     if (newCallingInfo == nullptr) {
400         LOG_ERROR("newCallingInfo is null.");
401         return;
402     }
403     CallingInfo callingInfo {
404         .callingPid = newCallingInfo->callingPid,
405         .callingUid = newCallingInfo->callingUid,
406         .callingTokenId = newCallingInfo->callingTokenId,
407         .activeStatus = ACTIVE_INVOKER,
408     };
409     NAPI_RemoteObject_setNewCallingInfo(env, callingInfo);
410 }
411 
InitAsyncCallParams(size_t argc,napi_env & env,napi_value * args)412 int32_t JsDataShareExtAbility::InitAsyncCallParams(size_t argc, napi_env &env, napi_value *args)
413 {
414     AsyncCallBackPoint *point = new (std::nothrow)AsyncCallBackPoint();
415     if (point == nullptr) {
416         return E_ERROR;
417     }
418     callbackResultNumber_ = -1;
419     callbackResultString_ = "";
420     callbackResultStringArr_ = {};
421     SetResultSet(nullptr);
422     SetRecvReply(false);
423     point->extAbility = std::static_pointer_cast<JsDataShareExtAbility>(shared_from_this());
424     napi_create_function(env, ASYNC_CALLBACK_NAME, CALLBACK_LENGTH,
425         JsDataShareExtAbility::AsyncCallback, point, &args[argc]);
426     napi_add_finalizer(env, args[argc], point,
427         [](napi_env env, void* point, void* finalize_hint) {
428             delete static_cast<AsyncCallBackPoint *>(point);
429         }, nullptr, nullptr);
430     return E_OK;
431 }
432 
GetSrcPath(std::string & srcPath)433 void JsDataShareExtAbility::GetSrcPath(std::string &srcPath)
434 {
435     if (!Extension::abilityInfo_->isStageBasedModel) {
436         /* temporary compatibility api8 + config.json */
437         srcPath.append(Extension::abilityInfo_->package);
438         srcPath.append("/assets/js/");
439         if (!Extension::abilityInfo_->srcPath.empty()) {
440             srcPath.append(Extension::abilityInfo_->srcPath);
441         }
442         srcPath.append("/").append(Extension::abilityInfo_->name).append(".abc");
443         return;
444     }
445 
446     if (!Extension::abilityInfo_->srcEntrance.empty()) {
447         srcPath.append(Extension::abilityInfo_->moduleName + "/");
448         srcPath.append(Extension::abilityInfo_->srcEntrance);
449         srcPath.erase(srcPath.rfind('.'));
450         srcPath.append(".abc");
451     }
452 }
453 
GetFileTypes(const Uri & uri,const std::string & mimeTypeFilter)454 std::vector<std::string> JsDataShareExtAbility::GetFileTypes(const Uri &uri, const std::string &mimeTypeFilter)
455 {
456     auto ret = DataShareExtAbility::GetFileTypes(uri, mimeTypeFilter);
457     HandleScope handleScope(jsRuntime_);
458     napi_env env = jsRuntime_.GetNapiEnv();
459     napi_handle_scope scope = nullptr;
460     napi_open_handle_scope(env, &scope);
461     if (scope == nullptr) {
462         return ret;
463     }
464     napi_value napiUri = nullptr;
465     napi_status status = napi_create_string_utf8(env, uri.ToString().c_str(), NAPI_AUTO_LENGTH, &napiUri);
466     if (status != napi_ok) {
467         LOG_ERROR("napi_create_string_utf8 status : %{public}d", status);
468         napi_close_handle_scope(env, scope);
469         return ret;
470     }
471     napi_value napiMimeTypeFilter = nullptr;
472     status = napi_create_string_utf8(env, mimeTypeFilter.c_str(), NAPI_AUTO_LENGTH, &napiMimeTypeFilter);
473     if (status != napi_ok) {
474         LOG_ERROR("napi_create_string_utf8 status : %{public}d", status);
475         napi_close_handle_scope(env, scope);
476         return ret;
477     }
478     napi_value argv[] = {napiUri, napiMimeTypeFilter};
479     //represents this function has 2 parameters
480     CallObjectMethod("getFileTypes", argv, 2);
481     napi_close_handle_scope(env, scope);
482     return ret;
483 }
484 
OpenFile(const Uri & uri,const std::string & mode)485 int JsDataShareExtAbility::OpenFile(const Uri &uri, const std::string &mode)
486 {
487     auto ret = DataShareExtAbility::OpenFile(uri, mode);
488     HandleScope handleScope(jsRuntime_);
489     napi_env env = jsRuntime_.GetNapiEnv();
490     napi_handle_scope scope = nullptr;
491     napi_open_handle_scope(env, &scope);
492     if (scope == nullptr) {
493         return ret;
494     }
495     napi_value napiUri = nullptr;
496     napi_status status = napi_create_string_utf8(env, uri.ToString().c_str(), NAPI_AUTO_LENGTH, &napiUri);
497     if (status != napi_ok) {
498         LOG_ERROR("napi_create_string_utf8 status : %{public}d", status);
499         napi_close_handle_scope(env, scope);
500         return ret;
501     }
502     napi_value napiMode = nullptr;
503     status = napi_create_string_utf8(env, mode.c_str(), NAPI_AUTO_LENGTH, &napiMode);
504     if (status != napi_ok) {
505         LOG_ERROR("napi_create_string_utf8 status : %{public}d", status);
506         napi_close_handle_scope(env, scope);
507         return ret;
508     }
509     napi_value argv[] = {napiUri, napiMode};
510     //represents this function has 2 parameters
511     CallObjectMethod("openFile", argv, 2);
512     napi_close_handle_scope(env, scope);
513     return ret;
514 }
515 
OpenRawFile(const Uri & uri,const std::string & mode)516 int JsDataShareExtAbility::OpenRawFile(const Uri &uri, const std::string &mode)
517 {
518     auto ret = DataShareExtAbility::OpenRawFile(uri, mode);
519     HandleScope handleScope(jsRuntime_);
520     napi_env env = jsRuntime_.GetNapiEnv();
521     napi_handle_scope scope = nullptr;
522     napi_open_handle_scope(env, &scope);
523     if (scope == nullptr) {
524         return ret;
525     }
526     napi_value napiUri = nullptr;
527     napi_status status = napi_create_string_utf8(env, uri.ToString().c_str(), NAPI_AUTO_LENGTH, &napiUri);
528     if (status != napi_ok) {
529         LOG_ERROR("napi_create_string_utf8 status : %{public}d", status);
530         napi_close_handle_scope(env, scope);
531         return ret;
532     }
533     napi_value napiMode = nullptr;
534     status = napi_create_string_utf8(env, mode.c_str(), NAPI_AUTO_LENGTH, &napiMode);
535     if (status != napi_ok) {
536         LOG_ERROR("napi_create_string_utf8 status : %{public}d", status);
537         napi_close_handle_scope(env, scope);
538         return ret;
539     }
540     napi_value argv[] = {napiUri, napiMode};
541     //represents this function has 2 parameters
542     CallObjectMethod("openRawFile", argv, 2, false);
543     napi_close_handle_scope(env, scope);
544     return ret;
545 }
546 
Insert(const Uri & uri,const DataShareValuesBucket & value)547 int JsDataShareExtAbility::Insert(const Uri &uri, const DataShareValuesBucket &value)
548 {
549     int ret = INVALID_VALUE;
550     ret = DataShareExtAbility::Insert(uri, value);
551     HandleScope handleScope(jsRuntime_);
552     napi_env env = jsRuntime_.GetNapiEnv();
553     napi_handle_scope scope = nullptr;
554     napi_open_handle_scope(env, &scope);
555     if (scope == nullptr) {
556         return ret;
557     }
558     napi_value napiUri = nullptr;
559     napi_status status = napi_create_string_utf8(env, uri.ToString().c_str(), NAPI_AUTO_LENGTH, &napiUri);
560     if (status != napi_ok) {
561         LOG_ERROR("napi_create_string_utf8 status : %{public}d", status);
562         napi_close_handle_scope(env, scope);
563         return ret;
564     }
565     napi_value napiValue = NewInstance(env, const_cast<DataShareValuesBucket&>(value));
566     if (napiValue == nullptr) {
567         LOG_ERROR("failed to make new instance of rdbValueBucket.");
568         napi_close_handle_scope(env, scope);
569         return ret;
570     }
571     napi_value argv[] = {napiUri, napiValue};
572     //represents this function has 2 parameters
573     CallObjectMethod("insert", argv, 2);
574     napi_close_handle_scope(env, scope);
575     return ret;
576 }
577 
Update(const Uri & uri,const DataSharePredicates & predicates,const DataShareValuesBucket & value)578 int JsDataShareExtAbility::Update(const Uri &uri, const DataSharePredicates &predicates,
579     const DataShareValuesBucket &value)
580 {
581     int ret = INVALID_VALUE;
582     ret = DataShareExtAbility::Update(uri, predicates, value);
583     HandleScope handleScope(jsRuntime_);
584     napi_env env = jsRuntime_.GetNapiEnv();
585     napi_handle_scope scope = nullptr;
586     napi_open_handle_scope(env, &scope);
587     if (scope == nullptr) {
588         return ret;
589     }
590     napi_value napiUri = nullptr;
591     napi_status status = napi_create_string_utf8(env, uri.ToString().c_str(), NAPI_AUTO_LENGTH, &napiUri);
592     if (status != napi_ok) {
593         LOG_ERROR("napi_create_string_utf8 status : %{public}d", status);
594         napi_close_handle_scope(env, scope);
595         return ret;
596     }
597 
598     napi_value napiPredicates = MakePredicates(env, predicates);
599     if (napiPredicates == nullptr) {
600         napi_close_handle_scope(env, scope);
601         return ret;
602     }
603 
604     napi_value napiValue = NewInstance(env, const_cast<DataShareValuesBucket&>(value));
605     if (napiValue == nullptr) {
606         LOG_ERROR("failed to make new instance of rdbValueBucket.");
607         napi_close_handle_scope(env, scope);
608         return ret;
609     }
610 
611     napi_value argv[] = {napiUri, napiPredicates, napiValue};
612     //represents this function has 3 parameters
613     CallObjectMethod("update", argv, 3);
614     napi_close_handle_scope(env, scope);
615     return ret;
616 }
617 
BatchUpdate(const UpdateOperations & operations,std::vector<BatchUpdateResult> & results)618 int JsDataShareExtAbility::BatchUpdate(const UpdateOperations &operations,
619     std::vector<BatchUpdateResult> &results)
620 {
621     int ret = DataShareExtAbility::BatchUpdate(operations, results);
622     HandleScope handleScope(jsRuntime_);
623     napi_env env = jsRuntime_.GetNapiEnv();
624     napi_handle_scope scope = nullptr;
625     napi_open_handle_scope(env, &scope);
626     if (scope == nullptr) {
627         return ret;
628     }
629     napi_value jsMap = nullptr;
630     napi_status status = napi_create_object(env, &jsMap);
631     if (status != napi_ok) {
632         LOG_ERROR("napi_create_object : %{public}d", status);
633         napi_close_handle_scope(env, scope);
634         return ret;
635     }
636     for (const auto &valueArray : operations) {
637         napi_value napiValues = nullptr;
638         status = napi_create_array(env, &napiValues);
639         if (status != napi_ok) {
640             LOG_ERROR("napi_create_array status : %{public}d", status);
641             napi_close_handle_scope(env, scope);
642             return ret;
643         }
644         int32_t index = 0;
645         for (const auto &value : valueArray.second) {
646             napi_value jsUpdateOperation = MakeUpdateOperation(env, value);
647             if (jsUpdateOperation == nullptr) {
648                 LOG_ERROR("MakeUpdateOperation failed");
649                 napi_close_handle_scope(env, scope);
650                 return ret;
651             }
652             napi_set_element(env, napiValues, index++, jsUpdateOperation);
653         }
654         napi_set_named_property(env, jsMap, valueArray.first.c_str(), napiValues);
655     }
656     napi_value argv[] = { jsMap };
657     CallObjectMethod("batchUpdate", argv, 1);
658     napi_close_handle_scope(env, scope);
659     return ret;
660 }
661 
Delete(const Uri & uri,const DataSharePredicates & predicates)662 int JsDataShareExtAbility::Delete(const Uri &uri, const DataSharePredicates &predicates)
663 {
664     int ret = INVALID_VALUE;
665     ret = DataShareExtAbility::Delete(uri, predicates);
666     HandleScope handleScope(jsRuntime_);
667     napi_env env = jsRuntime_.GetNapiEnv();
668     napi_handle_scope scope = nullptr;
669     napi_open_handle_scope(env, &scope);
670     if (scope == nullptr) {
671         return ret;
672     }
673     napi_value napiUri = nullptr;
674     napi_status status = napi_create_string_utf8(env, uri.ToString().c_str(), NAPI_AUTO_LENGTH, &napiUri);
675     if (status != napi_ok) {
676         LOG_ERROR("napi_create_string_utf8 status : %{public}d", status);
677         napi_close_handle_scope(env, scope);
678         return ret;
679     }
680 
681     napi_value napiPredicates = MakePredicates(env, predicates);
682     if (napiPredicates == nullptr) {
683         napi_close_handle_scope(env, scope);
684         return ret;
685     }
686 
687     napi_value argv[] = {napiUri, napiPredicates};
688     //represents this function has 2 parameters
689     CallObjectMethod("delete", argv, 2);
690     napi_close_handle_scope(env, scope);
691     return ret;
692 }
693 
Query(const Uri & uri,const DataSharePredicates & predicates,std::vector<std::string> & columns,DatashareBusinessError & businessError)694 std::shared_ptr<DataShareResultSet> JsDataShareExtAbility::Query(const Uri &uri,
695     const DataSharePredicates &predicates, std::vector<std::string> &columns, DatashareBusinessError &businessError)
696 {
697     std::shared_ptr<DataShareResultSet> ret;
698     ret = DataShareExtAbility::Query(uri, predicates, columns, businessError);
699 
700     HandleScope handleScope(jsRuntime_);
701     napi_env env = jsRuntime_.GetNapiEnv();
702     napi_handle_scope scope = nullptr;
703     napi_open_handle_scope(env, &scope);
704     if (scope == nullptr) {
705         return ret;
706     }
707     napi_value napiUri = nullptr;
708     napi_status status = napi_create_string_utf8(env, uri.ToString().c_str(), NAPI_AUTO_LENGTH, &napiUri);
709     if (status != napi_ok) {
710         LOG_ERROR("napi_create_string_utf8 status : %{public}d", status);
711         napi_close_handle_scope(env, scope);
712         return ret;
713     }
714 
715     napi_value napiPredicates = MakePredicates(env, predicates);
716     if (napiPredicates == nullptr) {
717         napi_close_handle_scope(env, scope);
718         return ret;
719     }
720 
721     napi_value napiColumns = nullptr;
722     if (!MakeNapiColumn(env, napiColumns, columns)) {
723         LOG_ERROR("MakeNapiColumn failed");
724         napi_close_handle_scope(env, scope);
725         return ret;
726     }
727 
728     napi_value argv[] = {napiUri, napiPredicates, napiColumns};
729     //represents this function has 3 parameters
730     CallObjectMethod("query", argv, 3);
731     napi_close_handle_scope(env, scope);
732     return ret;
733 }
734 
GetType(const Uri & uri)735 std::string JsDataShareExtAbility::GetType(const Uri &uri)
736 {
737     auto ret = DataShareExtAbility::GetType(uri);
738     HandleScope handleScope(jsRuntime_);
739     napi_env env = jsRuntime_.GetNapiEnv();
740     napi_handle_scope scope = nullptr;
741     napi_open_handle_scope(env, &scope);
742     if (scope == nullptr) {
743         return ret;
744     }
745     napi_value napiUri = nullptr;
746     napi_status status = napi_create_string_utf8(env, uri.ToString().c_str(), NAPI_AUTO_LENGTH, &napiUri);
747     if (status != napi_ok) {
748         LOG_ERROR("napi_create_string_utf8 status : %{public}d", status);
749         napi_close_handle_scope(env, scope);
750         return ret;
751     }
752     napi_value argv[] = {napiUri};
753     //represents this function has 1 parameter
754     CallObjectMethod("getType", argv, 1);
755     napi_close_handle_scope(env, scope);
756     return ret;
757 }
758 
BatchInsert(const Uri & uri,const std::vector<DataShareValuesBucket> & values)759 int JsDataShareExtAbility::BatchInsert(const Uri &uri, const std::vector<DataShareValuesBucket> &values)
760 {
761     int ret = INVALID_VALUE;
762     ret = DataShareExtAbility::BatchInsert(uri, values);
763 
764     HandleScope handleScope(jsRuntime_);
765     napi_env env = jsRuntime_.GetNapiEnv();
766     napi_handle_scope scope = nullptr;
767     napi_open_handle_scope(env, &scope);
768     if (scope == nullptr) {
769         return ret;
770     }
771     napi_value napiUri = nullptr;
772     napi_status status = napi_create_string_utf8(env, uri.ToString().c_str(), NAPI_AUTO_LENGTH, &napiUri);
773     if (status != napi_ok) {
774         LOG_ERROR("napi_create_string_utf8 status : %{public}d", status);
775         napi_close_handle_scope(env, scope);
776         return ret;
777     }
778 
779     napi_value napiValues = nullptr;
780     status = napi_create_array(env, &napiValues);
781     if (status != napi_ok) {
782         LOG_ERROR("napi_create_array status : %{public}d", status);
783         napi_close_handle_scope(env, scope);
784         return ret;
785     }
786     bool isArray = false;
787     if (napi_is_array(env, napiValues, &isArray) != napi_ok || !isArray) {
788         LOG_ERROR("JsDataShareExtAbility create array failed");
789         napi_close_handle_scope(env, scope);
790         return ret;
791     }
792     int32_t index = 0;
793     for (const auto &value : values) {
794         napi_value result = NewInstance(env, const_cast<DataShareValuesBucket&>(value));
795         if (result == nullptr) {
796             LOG_ERROR("failed to make new instance of rdbValueBucket.");
797             napi_close_handle_scope(env, scope);
798             return ret;
799         }
800         napi_set_element(env, napiValues, index++, result);
801     }
802     napi_value argv[] = {napiUri, napiValues};
803     //represents this function has 2 parameters
804     CallObjectMethod("batchInsert", argv, 2);
805     napi_close_handle_scope(env, scope);
806     return ret;
807 }
808 
RegisterObserver(const Uri & uri,const sptr<AAFwk::IDataAbilityObserver> & dataObserver)809 bool JsDataShareExtAbility::RegisterObserver(const Uri &uri, const sptr<AAFwk::IDataAbilityObserver> &dataObserver)
810 {
811     DataShareExtAbility::RegisterObserver(uri, dataObserver);
812     auto obsMgrClient = DataObsMgrClient::GetInstance();
813     if (obsMgrClient == nullptr) {
814         LOG_ERROR("obsMgrClient is nullptr");
815         return false;
816     }
817 
818     ErrCode ret = obsMgrClient->RegisterObserver(uri, dataObserver);
819     if (ret != ERR_OK) {
820         LOG_ERROR("obsMgrClient->RegisterObserver error return %{public}d", ret);
821         return false;
822     }
823     return true;
824 }
825 
UnregisterObserver(const Uri & uri,const sptr<AAFwk::IDataAbilityObserver> & dataObserver)826 bool JsDataShareExtAbility::UnregisterObserver(const Uri &uri, const sptr<AAFwk::IDataAbilityObserver> &dataObserver)
827 {
828     DataShareExtAbility::UnregisterObserver(uri, dataObserver);
829     auto obsMgrClient = DataObsMgrClient::GetInstance();
830     if (obsMgrClient == nullptr) {
831         LOG_ERROR("obsMgrClient is nullptr");
832         return false;
833     }
834 
835     ErrCode ret = obsMgrClient->UnregisterObserver(uri, dataObserver);
836     if (ret != ERR_OK) {
837         LOG_ERROR("obsMgrClient->UnregisterObserver error return %{public}d", ret);
838         return false;
839     }
840     return true;
841 }
842 
NotifyChange(const Uri & uri)843 bool JsDataShareExtAbility::NotifyChange(const Uri &uri)
844 {
845     DataShareExtAbility::NotifyChange(uri);
846     auto obsMgrClient = DataObsMgrClient::GetInstance();
847     if (obsMgrClient == nullptr) {
848         LOG_ERROR("obsMgrClient is nullptr");
849         return false;
850     }
851 
852     ErrCode ret = obsMgrClient->NotifyChange(uri);
853     if (ret != ERR_OK) {
854         LOG_ERROR("obsMgrClient->NotifyChange error return %{public}d", ret);
855         return false;
856     }
857     return true;
858 }
859 
NormalizeUri(const Uri & uri)860 Uri JsDataShareExtAbility::NormalizeUri(const Uri &uri)
861 {
862     auto ret = DataShareExtAbility::NormalizeUri(uri);
863     HandleScope handleScope(jsRuntime_);
864     napi_env env = jsRuntime_.GetNapiEnv();
865     napi_handle_scope scope = nullptr;
866     napi_open_handle_scope(env, &scope);
867     if (scope == nullptr) {
868         return ret;
869     }
870     napi_value napiUri = nullptr;
871     napi_status status = napi_create_string_utf8(env, uri.ToString().c_str(), NAPI_AUTO_LENGTH, &napiUri);
872     if (status != napi_ok) {
873         LOG_ERROR("napi_create_string_utf8 status : %{public}d", status);
874         napi_close_handle_scope(env, scope);
875         return ret;
876     }
877     napi_value argv[] = {napiUri};
878     //represents this function has 1 parameter
879     CallObjectMethod("normalizeUri", argv, 1);
880     napi_close_handle_scope(env, scope);
881     return ret;
882 }
883 
DenormalizeUri(const Uri & uri)884 Uri JsDataShareExtAbility::DenormalizeUri(const Uri &uri)
885 {
886     auto ret = DataShareExtAbility::DenormalizeUri(uri);
887     HandleScope handleScope(jsRuntime_);
888     napi_env env = jsRuntime_.GetNapiEnv();
889     napi_handle_scope scope = nullptr;
890     napi_open_handle_scope(env, &scope);
891     if (scope == nullptr) {
892         return ret;
893     }
894     napi_value napiUri = nullptr;
895     napi_status status = napi_create_string_utf8(env, uri.ToString().c_str(), NAPI_AUTO_LENGTH, &napiUri);
896     if (status != napi_ok) {
897         LOG_ERROR("napi_create_string_utf8 status : %{public}d", status);
898         napi_close_handle_scope(env, scope);
899         return ret;
900     }
901     napi_value argv[] = {napiUri};
902     //represents this function has 1 parameter
903     CallObjectMethod("denormalizeUri", argv, 1);
904     napi_close_handle_scope(env, scope);
905     return ret;
906 }
907 
MakePredicates(napi_env env,const DataSharePredicates & predicates)908 napi_value JsDataShareExtAbility::MakePredicates(napi_env env, const DataSharePredicates &predicates)
909 {
910     std::shared_ptr<DataSharePredicates> predicatesPtr = std::make_shared<DataSharePredicates>(predicates);
911     if (predicatesPtr == nullptr) {
912         LOG_ERROR("No memory allocated for predicates");
913         return nullptr;
914     }
915     napi_value napiPredicates = DataSharePredicatesProxy::NewInstance(env, predicatesPtr);
916     if (napiPredicates == nullptr) {
917         LOG_ERROR("failed to make new instance of DataSharePredicates.");
918     }
919     return napiPredicates;
920 }
921 
UnWrapBusinessError(napi_env env,napi_value info,DatashareBusinessError & businessError)922 void JsDataShareExtAbility::UnWrapBusinessError(napi_env env, napi_value info,
923     DatashareBusinessError& businessError)
924 {
925     std::string code = UnWrapProperty(env, info, "code");
926     businessError.SetCode(code);
927     std::string message = UnWrapProperty(env, info, "message");
928     businessError.SetMessage(message);
929 }
930 
UnWrapProperty(napi_env env,napi_value info,const std::string & key)931 std::string JsDataShareExtAbility::UnWrapProperty(napi_env env, napi_value info, const std::string &key)
932 {
933     napi_valuetype type = UnWrapPropertyType(env, info, key);
934     if (type == napi_valuetype::napi_number) {
935         int value;
936         UnwrapInt32ByPropertyName(env, info, key.c_str(), value);
937         return std::to_string(value);
938     } else if (type == napi_valuetype::napi_string) {
939         std::string value;
940         UnwrapStringByPropertyName(env, info, key.c_str(), value);
941         return value;
942     } else {
943         LOG_ERROR("ValueType should be napi_number or napi_string, property is %{public}s", key.c_str());
944         return "";
945     }
946 }
947 
UnWrapPropertyType(napi_env env,napi_value info,const std::string & propertyKey)948 napi_valuetype JsDataShareExtAbility::UnWrapPropertyType(napi_env env, napi_value info,
949     const std::string &propertyKey)
950 {
951     napi_value key = nullptr;
952     napi_status status = napi_create_string_utf8(env, propertyKey.c_str(), propertyKey.size(), &key);
953     if (status != napi_ok) {
954         LOG_ERROR("napi_create_string_utf8 failed, status is %{public}d, propertyKey is %{public}s",
955             status, propertyKey.c_str());
956         return napi_undefined;
957     }
958 
959     bool result = false;
960     napi_has_property(env, info, key, &result);
961     if (!result) {
962         LOG_WARN("not contains property is %{public}s", propertyKey.c_str());
963         return napi_undefined;
964     }
965 
966     napi_value value = nullptr;
967     status = napi_get_property(env, info, key, &value);
968     if (status != napi_ok) {
969         LOG_ERROR("failed to napi_get_property, status is %{public}d, propertyKey is %{public}s",
970             status, propertyKey.c_str());
971         return napi_undefined;
972     }
973 
974     napi_valuetype type = napi_undefined;
975     napi_typeof(env, value, &type);
976     return type;
977 }
978 
NotifyToDataShareService()979 void JsDataShareExtAbility::NotifyToDataShareService()
980 {
981     auto manager = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
982     if (manager == nullptr) {
983         LOG_ERROR("get system ability manager failed");
984         return;
985     }
986     auto remoteObject = manager->CheckSystemAbility(DISTRIBUTED_KV_DATA_SERVICE_ABILITY_ID);
987     if (remoteObject == nullptr) {
988         LOG_ERROR("CheckSystemAbility failed");
989         return;
990     }
991     auto serviceProxy = std::make_shared<DataShareKvServiceProxy>(remoteObject);
992     if (serviceProxy == nullptr) {
993         LOG_ERROR("make_shared failed");
994         return;
995     }
996     auto remote = serviceProxy->GetFeatureInterface("data_share");
997     if (remote == nullptr) {
998         LOG_ERROR("Get DataShare service failed!");
999         return;
1000     }
1001     MessageParcel data;
1002     MessageParcel reply;
1003     MessageOption option(MessageOption::TF_ASYNC);
1004     if (!data.WriteInterfaceToken(IDataShareService::GetDescriptor())) {
1005         LOG_ERROR("Write descriptor failed!");
1006         return;
1007     }
1008     remote->SendRequest(
1009         static_cast<uint32_t>(DataShareServiceInterfaceCode::DATA_SHARE_SERVICE_CMD_NOTIFY), data, reply, option);
1010 }
1011 
MakeUpdateOperation(napi_env env,const UpdateOperation & updateOperation)1012 napi_value JsDataShareExtAbility::MakeUpdateOperation(napi_env env, const UpdateOperation &updateOperation)
1013 {
1014     napi_value jsValueBucket = NewInstance(env, const_cast<DataShareValuesBucket&>(updateOperation.valuesBucket));
1015     napi_value jsPredicates = MakePredicates(env, updateOperation.predicates);
1016     if (jsValueBucket == nullptr || jsPredicates == nullptr) {
1017         LOG_ERROR("failed to make new instance of UpdateOperation.");
1018         return nullptr;
1019     }
1020     napi_value jsUpdateOperation = nullptr;
1021     napi_status status = napi_create_object(env, &jsUpdateOperation);
1022     if (status != napi_ok) {
1023         LOG_ERROR("JsDataShareExtAbility create object failed");
1024         return nullptr;
1025     }
1026     std::string valuesKey = "values";
1027     std::string presKey = "predicates";
1028     napi_value jsValueKey = DataShareJSUtils::Convert2JSValue(env, valuesKey);
1029     napi_value jsPresKey = DataShareJSUtils::Convert2JSValue(env, presKey);
1030     napi_set_property(env, jsUpdateOperation, jsValueKey, jsValueBucket);
1031     napi_set_property(env, jsUpdateOperation, jsPresKey, jsPredicates);
1032     return jsUpdateOperation;
1033 }
1034 
MakeNapiColumn(napi_env env,napi_value & napiColumns,const std::vector<std::string> & columns)1035 bool MakeNapiColumn(napi_env env, napi_value &napiColumns, const std::vector<std::string> &columns)
1036 {
1037     napi_status status = napi_create_array(env, &napiColumns);
1038     if (status != napi_ok) {
1039         LOG_ERROR("napi_create_array status : %{public}d", status);
1040         return false;
1041     }
1042 
1043     bool isArray = false;
1044     if (napi_is_array(env, napiColumns, &isArray) != napi_ok || !isArray) {
1045         LOG_ERROR("JsDataShareExtAbility create array failed");
1046         return false;
1047     }
1048 
1049     int32_t index = 0;
1050     for (const auto &column : columns) {
1051         napi_value result = nullptr;
1052         napi_create_string_utf8(env, column.c_str(), column.length(), &result);
1053         napi_set_element(env, napiColumns, index++, result);
1054     }
1055 
1056     return true;
1057 }
1058 } // namespace DataShare
1059 } // namespace OHOS