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 "datashare_helper.h"
17
18 #include "datashare_result_set.h"
19 #include "data_share_manager.h"
20 #include "data_ability_observer_interface.h"
21 #include "dataobs_mgr_client.h"
22 #include "datashare_log.h"
23 #include "idatashare.h"
24
25 namespace OHOS {
26 namespace DataShare {
27 using namespace AppExecFwk;
28 namespace {
29 const std::string SCHEME_DATASHARE = "datashare";
30 constexpr int INVALID_VALUE = -1;
31 } // namespace
32
DataShareHelper(const sptr<IRemoteObject> & token,const Uri & uri,std::shared_ptr<DataShareConnection> dataShareConnection)33 DataShareHelper::DataShareHelper(const sptr<IRemoteObject> &token, const Uri &uri,
34 std::shared_ptr<DataShareConnection> dataShareConnection)
35 {
36 LOG_INFO("DataShareHelper::DataShareHelper start");
37 token_ = token;
38 uri_ = uri;
39 dataShareConnection_ = dataShareConnection;
40 }
41
DataShareHelper(const sptr<IRemoteObject> & token,const Uri & uri)42 DataShareHelper::DataShareHelper(const sptr<IRemoteObject> &token, const Uri &uri)
43 {
44 LOG_INFO("DataShareHelper::DataShareHelper start");
45 token_ = token;
46 uri_ = uri;
47 isDataShareService_ = (uri_.GetQuery().find("Proxy=true") != std::string::npos);
48 LOG_INFO("DataShareHelper::DataShareHelper end");
49 }
50
~DataShareHelper()51 DataShareHelper::~DataShareHelper()
52 {
53 }
54
55 /**
56 * @brief You can use this method to specify the Uri of the data to operate and set the binding relationship
57 * between the ability using the Data template (data share for short) and the associated client process in
58 * a DataShareHelper instance.
59 *
60 * @param context Indicates the Context object on OHOS.
61 * @param strUri Indicates the database table or disk file to operate.
62 *
63 * @return Returns the created DataShareHelper instance.
64 */
Creator(const std::shared_ptr<Context> & context,const std::string & strUri)65 std::shared_ptr<DataShareHelper> DataShareHelper::Creator(
66 const std::shared_ptr<Context> &context, const std::string &strUri)
67 {
68 if (context == nullptr) {
69 LOG_ERROR("DataShareHelper::Creator failed, context == nullptr");
70 return nullptr;
71 }
72 sptr<IRemoteObject> token = context->GetToken();
73 return Creator(token, strUri);
74 }
75
76 /**
77 * @brief You can use this method to specify the Uri of the data to operate and set the binding relationship
78 * between the ability using the Data template (data share for short) and the associated client process in
79 * a DataShareHelper instance.
80 *
81 * @param context Indicates the Context object on OHOS.
82 * @param strUri Indicates the database table or disk file to operate.
83 *
84 * @return Returns the created DataShareHelper instance.
85 */
Creator(const std::shared_ptr<OHOS::AbilityRuntime::Context> & context,const std::string & strUri)86 std::shared_ptr<DataShareHelper> DataShareHelper::Creator(
87 const std::shared_ptr<OHOS::AbilityRuntime::Context> &context, const std::string &strUri)
88 {
89 if (context == nullptr) {
90 LOG_ERROR("DataShareHelper::Creator failed, context == nullptr");
91 return nullptr;
92 }
93 sptr<IRemoteObject> token = context->GetToken();
94 return Creator(token, strUri);
95 }
96
97 /**
98 * @brief You can use this method to specify the Uri of the data to operate and set the binding relationship
99 * between the ability using the Data template (data share for short) and the associated client process in
100 * a DataShareHelper instance.
101 *
102 * @param token Indicates the System token.
103 * @param strUri Indicates the database table or disk file to operate.
104 *
105 * @return Returns the created DataShareHelper instance.
106 */
Creator(const sptr<IRemoteObject> & token,const std::string & strUri)107 std::shared_ptr<DataShareHelper> DataShareHelper::Creator(const sptr<IRemoteObject> &token, const std::string &strUri)
108 {
109 if (token == nullptr) {
110 LOG_ERROR("token == nullptr");
111 return nullptr;
112 }
113
114 Uri uri(strUri);
115 if (uri.GetScheme() != SCHEME_DATASHARE) {
116 LOG_ERROR("the Scheme is not datashare, Scheme: %{public}s", uri.GetScheme().c_str());
117 return nullptr;
118 }
119 if ((uri.GetQuery().find("Proxy=true") != std::string::npos) &&
120 DataShareManager::GetDataShareService() != nullptr) {
121 DataShareHelper *dataShareHelper = new (std::nothrow) DataShareHelper(token, uri);
122 if (dataShareHelper) {
123 return std::shared_ptr<DataShareHelper>(dataShareHelper);
124 }
125 LOG_ERROR("create DataShareHelper failed");
126 }
127
128 sptr<DataShareConnection> connection = new (std::nothrow) DataShareConnection(uri);
129 if (connection == nullptr) {
130 LOG_ERROR("create dataShareConnection failed.");
131 return nullptr;
132 }
133 auto dataShareConnection = std::shared_ptr<DataShareConnection>(connection.GetRefPtr(),
134 [holder = connection](const auto *) {
135 holder->DisconnectDataShareExtAbility();
136 });
137 if (!dataShareConnection->ConnectDataShareExtAbility(uri, token)) {
138 LOG_ERROR("connect failed");
139 return nullptr;
140 }
141
142 DataShareHelper *ptrDataShareHelper =
143 new (std::nothrow) DataShareHelper(token, uri, dataShareConnection);
144 if (ptrDataShareHelper == nullptr) {
145 LOG_ERROR("create DataShareHelper failed");
146 dataShareConnection = nullptr;
147 return nullptr;
148 }
149
150 return std::shared_ptr<DataShareHelper>(ptrDataShareHelper);
151 }
152
153 /**
154 * @brief Releases the client resource of the data share.
155 * You should call this method to releases client resource after the data operations are complete.
156 *
157 * @return Returns true if the resource is successfully released; returns false otherwise.
158 */
Release()159 bool DataShareHelper::Release()
160 {
161 LOG_INFO("Release Start");
162 dataShareConnection_ = nullptr;
163 uri_ = Uri("");
164 return true;
165 }
166
167 /**
168 * @brief Obtains the MIME types of files supported.
169 *
170 * @param uri Indicates the path of the files to obtain.
171 * @param mimeTypeFilter Indicates the MIME types of the files to obtain. This parameter cannot be null.
172 *
173 * @return Returns the matched MIME types. If there is no match, null is returned.
174 */
GetFileTypes(Uri & uri,const std::string & mimeTypeFilter)175 std::vector<std::string> DataShareHelper::GetFileTypes(Uri &uri, const std::string &mimeTypeFilter)
176 {
177 std::vector<std::string> matchedMIMEs;
178 auto connection = dataShareConnection_;
179 if (connection == nullptr) {
180 LOG_ERROR("dataShareConnection_ is nullptr");
181 return matchedMIMEs;
182 }
183
184 if (!connection->ConnectDataShareExtAbility(uri_, token_)) {
185 LOG_ERROR("dataShareProxy is nullptr");
186 return matchedMIMEs;
187 }
188
189 auto proxy = connection->GetDataShareProxy();
190 if (proxy != nullptr) {
191 matchedMIMEs = proxy->GetFileTypes(uri, mimeTypeFilter);
192 }
193 return matchedMIMEs;
194 }
195
196 /**
197 * @brief Opens a file in a specified remote path.
198 *
199 * @param uri Indicates the path of the file to open.
200 * @param mode Indicates the file open mode, which can be "r" for read-only access, "w" for write-only access
201 * (erasing whatever data is currently in the file), "wt" for write access that truncates any existing file,
202 * "wa" for write-only access to append to any existing data, "rw" for read and write access on any existing data,
203 * or "rwt" for read and write access that truncates any existing file.
204 *
205 * @return Returns the file descriptor.
206 */
OpenFile(Uri & uri,const std::string & mode)207 int DataShareHelper::OpenFile(Uri &uri, const std::string &mode)
208 {
209 int fd = INVALID_VALUE;
210 auto connection = dataShareConnection_;
211 if (connection == nullptr) {
212 LOG_ERROR("dataShareConnection_ is nullptr");
213 return fd;
214 }
215
216 if (!connection->ConnectDataShareExtAbility(uri_, token_)) {
217 LOG_ERROR("dataShareProxy is nullptr");
218 return fd;
219 }
220
221 auto proxy = connection->GetDataShareProxy();
222 if (proxy != nullptr) {
223 fd = proxy->OpenFile(uri, mode);
224 }
225 return fd;
226 }
227
228 /**
229 * @brief This is like openFile, open a file that need to be able to return sub-sections of files,often assets
230 * inside of their .hap.
231 *
232 * @param uri Indicates the path of the file to open.
233 * @param mode Indicates the file open mode, which can be "r" for read-only access, "w" for write-only access
234 * (erasing whatever data is currently in the file), "wt" for write access that truncates any existing file,
235 * "wa" for write-only access to append to any existing data, "rw" for read and write access on any existing
236 * data, or "rwt" for read and write access that truncates any existing file.
237 *
238 * @return Returns the RawFileDescriptor object containing file descriptor.
239 */
OpenRawFile(Uri & uri,const std::string & mode)240 int DataShareHelper::OpenRawFile(Uri &uri, const std::string &mode)
241 {
242 int fd = INVALID_VALUE;
243 auto connection = dataShareConnection_;
244 if (connection == nullptr) {
245 LOG_ERROR("dataShareConnection_ is nullptr");
246 return fd;
247 }
248
249 if (!connection->ConnectDataShareExtAbility(uri_, token_)) {
250 LOG_ERROR("dataShareProxy is nullptr");
251 return fd;
252 }
253
254 auto proxy = connection->GetDataShareProxy();
255 if (proxy != nullptr) {
256 fd = proxy->OpenRawFile(uri, mode);
257 }
258 return fd;
259 }
260
261 /**
262 * @brief Inserts a single data record into the database.
263 *
264 * @param uri Indicates the path of the data to operate.
265 * @param value Indicates the data record to insert. If this parameter is null, a blank row will be inserted.
266 *
267 * @return Returns the index of the inserted data record.
268 */
Insert(Uri & uri,const DataShareValuesBucket & value)269 int DataShareHelper::Insert(Uri &uri, const DataShareValuesBucket &value)
270 {
271 int index = INVALID_VALUE;
272 if (isDataShareService_) {
273 auto service = DataShareManager::GetDataShareService();
274 if (!service) {
275 return index;
276 }
277 return service->Insert(uri.ToString(), value);
278 }
279 auto connection = dataShareConnection_;
280 if (connection == nullptr) {
281 LOG_ERROR("dataShareConnection_ is nullptr");
282 return index;
283 }
284
285 if (!connection->ConnectDataShareExtAbility(uri_, token_)) {
286 LOG_ERROR("dataShareProxy is nullptr");
287 return index;
288 }
289
290 auto proxy = connection->GetDataShareProxy();
291 if (proxy != nullptr) {
292 index = proxy->Insert(uri, value);
293 }
294 return index;
295 }
296
297 /**
298 * @brief Updates data records in the database.
299 *
300 * @param uri Indicates the path of data to update.
301 * @param predicates Indicates filter criteria. You should define the processing logic when this parameter is null.
302 * @param value Indicates the data to update. This parameter can be null.
303 *
304 * @return Returns the number of data records updated.
305 */
Update(Uri & uri,const DataSharePredicates & predicates,const DataShareValuesBucket & value)306 int DataShareHelper::Update(
307 Uri &uri, const DataSharePredicates &predicates, const DataShareValuesBucket &value)
308 {
309 int index = INVALID_VALUE;
310 if (isDataShareService_) {
311 auto service = DataShareManager::GetDataShareService();
312 if (!service) {
313 return index;
314 }
315 return service->Update(uri.ToString(), predicates, value);
316 }
317
318 auto connection = dataShareConnection_;
319 if (connection == nullptr) {
320 LOG_ERROR("dataShareConnection_ is nullptr");
321 return index;
322 }
323
324 if (!connection->ConnectDataShareExtAbility(uri_, token_)) {
325 LOG_ERROR("dataShareProxy is nullptr");
326 return index;
327 }
328
329 auto proxy = connection->GetDataShareProxy();
330 if (proxy != nullptr) {
331 index = proxy->Update(uri, predicates, value);
332 }
333 return index;
334 }
335
336 /**
337 * @brief Deletes one or more data records from the database.
338 *
339 * @param uri Indicates the path of the data to operate.
340 * @param predicates Indicates filter criteria. You should define the processing logic when this parameter is null.
341 *
342 * @return Returns the number of data records deleted.
343 */
Delete(Uri & uri,const DataSharePredicates & predicates)344 int DataShareHelper::Delete(Uri &uri, const DataSharePredicates &predicates)
345 {
346 int index = INVALID_VALUE;
347 if (isDataShareService_) {
348 auto service = DataShareManager::GetDataShareService();
349 if (!service) {
350 return index;
351 }
352 return service->Delete(uri.ToString(), predicates);
353 }
354
355 auto connection = dataShareConnection_;
356 if (connection == nullptr) {
357 LOG_ERROR("dataShareConnection_ is nullptr");
358 return index;
359 }
360
361 if (!connection->ConnectDataShareExtAbility(uri_, token_)) {
362 LOG_ERROR("dataShareProxy is nullptr");
363 return index;
364 }
365
366 auto proxy = connection->GetDataShareProxy();
367 if (proxy != nullptr) {
368 index = proxy->Delete(uri, predicates);
369 }
370 return index;
371 }
372
373 /**
374 * @brief Deletes one or more data records from the database.
375 *
376 * @param uri Indicates the path of data to query.
377 * @param predicates Indicates filter criteria. You should define the processing logic when this parameter is null.
378 * @param columns Indicates the columns to query. If this parameter is null, all columns are queried.
379 *
380 * @return Returns the query result.
381 */
Query(Uri & uri,const DataSharePredicates & predicates,std::vector<std::string> & columns)382 std::shared_ptr<DataShareResultSet> DataShareHelper::Query(
383 Uri &uri, const DataSharePredicates &predicates, std::vector<std::string> &columns)
384 {
385 std::shared_ptr<DataShareResultSet> resultset = nullptr;
386 if (isDataShareService_) {
387 auto service = DataShareManager::GetDataShareService();
388 if (!service) {
389 return nullptr;
390 }
391 return service->Query(uri.ToString(), predicates, columns);
392 }
393
394 auto connection = dataShareConnection_;
395 if (connection == nullptr) {
396 LOG_ERROR("dataShareConnection_ is nullptr");
397 return resultset;
398 }
399
400 if (!connection->ConnectDataShareExtAbility(uri_, token_)) {
401 LOG_ERROR("dataShareProxy is nullptr");
402 return resultset;
403 }
404
405 auto proxy = connection->GetDataShareProxy();
406 if (proxy != nullptr) {
407 resultset = proxy->Query(uri, predicates, columns);
408 }
409 return resultset;
410 }
411
412 /**
413 * @brief Obtains the MIME type matching the data specified by the URI of the data share. This method should be
414 * implemented by a data share. Data abilities supports general data types, including text, HTML, and JPEG.
415 *
416 * @param uri Indicates the URI of the data.
417 *
418 * @return Returns the MIME type that matches the data specified by uri.
419 */
GetType(Uri & uri)420 std::string DataShareHelper::GetType(Uri &uri)
421 {
422 std::string type;
423
424 auto connection = dataShareConnection_;
425 if (connection == nullptr) {
426 LOG_ERROR("dataShareConnection_ is nullptr");
427 return type;
428 }
429
430 if (!connection->ConnectDataShareExtAbility(uri_, token_)) {
431 LOG_ERROR("dataShareProxy is nullptr");
432 return type;
433 }
434
435 auto proxy = connection->GetDataShareProxy();
436 if (proxy != nullptr) {
437 type = proxy->GetType(uri);
438 }
439 return type;
440 }
441
442 /**
443 * @brief Inserts multiple data records into the database.
444 *
445 * @param uri Indicates the path of the data to operate.
446 * @param values Indicates the data records to insert.
447 *
448 * @return Returns the number of data records inserted.
449 */
BatchInsert(Uri & uri,const std::vector<DataShareValuesBucket> & values)450 int DataShareHelper::BatchInsert(Uri &uri, const std::vector<DataShareValuesBucket> &values)
451 {
452 int ret = INVALID_VALUE;
453 auto connection = dataShareConnection_;
454 if (connection == nullptr) {
455 LOG_ERROR("dataShareConnection_ is nullptr");
456 return ret;
457 }
458
459 if (!connection->ConnectDataShareExtAbility(uri_, token_)) {
460 LOG_ERROR("dataShareProxy is nullptr");
461 return ret;
462 }
463
464 auto proxy = connection->GetDataShareProxy();
465 if (proxy != nullptr) {
466 ret = proxy->BatchInsert(uri, values);
467 }
468 return ret;
469 }
470
471 /**
472 * @brief Registers an observer to DataObsMgr specified by the given Uri.
473 *
474 * @param uri, Indicates the path of the data to operate.
475 * @param dataObserver, Indicates the IDataAbilityObserver object.
476 */
RegisterObserver(const Uri & uri,const sptr<AAFwk::IDataAbilityObserver> & dataObserver)477 void DataShareHelper::RegisterObserver(const Uri &uri, const sptr<AAFwk::IDataAbilityObserver> &dataObserver)
478 {
479 LOG_INFO("Start");
480 if (dataObserver == nullptr) {
481 LOG_ERROR("dataObserver is nullptr");
482 return;
483 }
484 if (isDataShareService_) {
485 if (!RegObserver(uri, dataObserver)) {
486 LOG_ERROR("RegisterObserver failed");
487 }
488 return;
489 }
490
491 auto connection = dataShareConnection_;
492 if (connection == nullptr) {
493 LOG_ERROR("dataShareConnection_ is nullptr");
494 return;
495 }
496
497 if (!connection->ConnectDataShareExtAbility(uri, token_)) {
498 LOG_ERROR("connect failed");
499 return;
500 }
501
502 auto proxy = connection->GetDataShareProxy();
503 if (proxy == nullptr) {
504 LOG_ERROR("proxy has disconnected");
505 return;
506 }
507 proxy->RegisterObserver(uri, dataObserver);
508 }
509
510 /**
511 * @brief Deregisters an observer used for DataObsMgr specified by the given Uri.
512 *
513 * @param uri, Indicates the path of the data to operate.
514 * @param dataObserver, Indicates the IDataAbilityObserver object.
515 */
UnregisterObserver(const Uri & uri,const sptr<AAFwk::IDataAbilityObserver> & dataObserver)516 void DataShareHelper::UnregisterObserver(const Uri &uri, const sptr<AAFwk::IDataAbilityObserver> &dataObserver)
517 {
518 LOG_INFO("Start");
519 if (dataObserver == nullptr) {
520 LOG_ERROR("dataObserver is nullptr");
521 return;
522 }
523
524 if (isDataShareService_) {
525 if (!UnregObserver(uri, dataObserver)) {
526 LOG_ERROR("UnregisterObserver failed");
527 }
528 return;
529 }
530
531 auto connection = dataShareConnection_;
532 if (connection == nullptr) {
533 LOG_ERROR("dataShareConnection_ is nullptr");
534 return;
535 }
536 auto proxy = connection->GetDataShareProxy();
537 if (proxy == nullptr) {
538 LOG_ERROR("dataShareConnection_->GetDataShareProxy() is nullptr");
539 return;
540 }
541 proxy->UnregisterObserver(uri, dataObserver);
542 }
543
544 /**
545 * @brief Notifies the registered observers of a change to the data resource specified by Uri.
546 *
547 * @param uri, Indicates the path of the data to operate.
548 */
NotifyChange(const Uri & uri)549 void DataShareHelper::NotifyChange(const Uri &uri)
550 {
551 auto connection = dataShareConnection_;
552 if (connection == nullptr) {
553 LOG_ERROR("dataShareConnection_ is nullptr");
554 return;
555 }
556
557 if (!connection->ConnectDataShareExtAbility(uri_, token_)) {
558 LOG_ERROR("dataShareProxy is nullptr");
559 return;
560 }
561
562 auto proxy = connection->GetDataShareProxy();
563 if (proxy != nullptr) {
564 proxy->NotifyChange(uri);
565 }
566 }
567
568 /**
569 * @brief Converts the given uri that refer to the data share into a normalized URI. A normalized URI can be used
570 * across devices, persisted, backed up, and restored. It can refer to the same item in the data share even if the
571 * context has changed. If you implement URI normalization for a data share, you must also implement
572 * denormalizeUri(ohos.utils.net.Uri) to enable URI denormalization. After this feature is enabled, URIs passed to any
573 * method that is called on the data share must require normalization verification and denormalization. The default
574 * implementation of this method returns null, indicating that this data share does not support URI normalization.
575 *
576 * @param uri Indicates the Uri object to normalize.
577 *
578 * @return Returns the normalized Uri object if the data share supports URI normalization; returns null otherwise.
579 */
NormalizeUri(Uri & uri)580 Uri DataShareHelper::NormalizeUri(Uri &uri)
581 {
582 Uri uriValue("");
583 auto connection = dataShareConnection_;
584 if (connection == nullptr) {
585 LOG_ERROR("dataShareConnection_ is nullptr");
586 return uriValue;
587 }
588
589 if (!connection->ConnectDataShareExtAbility(uri_, token_)) {
590 LOG_ERROR("dataShareProxy is nullptr");
591 return uriValue;
592 }
593
594 auto proxy = connection->GetDataShareProxy();
595 if (proxy != nullptr) {
596 uriValue = proxy->NormalizeUri(uri);
597 }
598 return uriValue;
599 }
600
601 /**
602 * @brief Converts the given normalized uri generated by normalizeUri(ohos.utils.net.Uri) into a denormalized one.
603 * The default implementation of this method returns the original URI passed to it.
604 *
605 * @param uri uri Indicates the Uri object to denormalize.
606 *
607 * @return Returns the denormalized Uri object if the denormalization is successful; returns the original Uri passed to
608 * this method if there is nothing to do; returns null if the data identified by the original Uri cannot be found in
609 * the current environment.
610 */
DenormalizeUri(Uri & uri)611 Uri DataShareHelper::DenormalizeUri(Uri &uri)
612 {
613 Uri uriValue("");
614 auto connection = dataShareConnection_;
615 if (connection == nullptr) {
616 LOG_ERROR("dataShareConnection_ is nullptr");
617 return uriValue;
618 }
619
620 if (!connection->ConnectDataShareExtAbility(uri_, token_)) {
621 LOG_ERROR("dataShareProxy is nullptr");
622 return uriValue;
623 }
624
625 auto proxy = connection->GetDataShareProxy();
626 if (proxy != nullptr) {
627 uriValue = proxy->DenormalizeUri(uri);
628 }
629 return uriValue;
630 }
631
RegObserver(const Uri & uri,const sptr<AAFwk::IDataAbilityObserver> & dataObserver)632 bool DataShareHelper::RegObserver (const Uri &uri, const sptr<AAFwk::IDataAbilityObserver> &dataObserver)
633 {
634 auto obsMgrClient = OHOS::AAFwk::DataObsMgrClient::GetInstance();
635 if (obsMgrClient == nullptr) {
636 LOG_ERROR("get DataObsMgrClient failed");
637 return false;
638 }
639 ErrCode ret = obsMgrClient->RegisterObserver(uri, dataObserver);
640 if (ret != ERR_OK) {
641 return false;
642 }
643 return true;
644 }
UnregObserver(const Uri & uri,const sptr<AAFwk::IDataAbilityObserver> & dataObserver)645 bool DataShareHelper::UnregObserver (const Uri &uri, const sptr<AAFwk::IDataAbilityObserver> &dataObserver)
646 {
647 auto obsMgrClient = OHOS::AAFwk::DataObsMgrClient::GetInstance();
648 if (obsMgrClient == nullptr) {
649 LOG_ERROR("get DataObsMgrClient failed");
650 return false;
651 }
652 ErrCode ret = obsMgrClient->UnregisterObserver(uri, dataObserver);
653 if (ret != ERR_OK) {
654 LOG_ERROR("UnregisterObserver failed");
655 return false;
656 }
657 return true;
658 }
659 } // namespace DataShare
660 } // namespace OHOS