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