• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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