1 /*
2 * Copyright (c) 2021-2023 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 "calllog_ability.h"
17
18 #include <mutex>
19
20 #include "common.h"
21 #include "contacts_common_event.h"
22 #include "contacts_datashare_stub_impl.h"
23 #include "datashare_ext_ability_context.h"
24 #include "datashare_predicates.h"
25 #include "file_utils.h"
26 #include "predicates_convert.h"
27 #include "rdb_predicates.h"
28 #include "rdb_utils.h"
29 #include "sql_analyzer.h"
30 #include "uri_utils.h"
31
32 namespace OHOS {
33 namespace AbilityRuntime {
34 namespace {
35 std::mutex g_mutex;
36 }
37 std::shared_ptr<Contacts::CallLogDataBase> CallLogAbility::callLogDataBase_ = nullptr;
38 std::map<std::string, int> CallLogAbility::uriValueMap_ = {
39 {"/com.ohos.calllogability/calls/calllog", Contacts::CALLLOG}
40 };
41
Create()42 CallLogAbility* CallLogAbility::Create()
43 {
44 return new CallLogAbility();
45 }
46
CallLogAbility()47 CallLogAbility::CallLogAbility() : DataShareExtAbility()
48 {
49 }
50
~CallLogAbility()51 CallLogAbility::~CallLogAbility()
52 {
53 }
54
OnConnect(const AAFwk::Want & want)55 sptr<IRemoteObject> CallLogAbility::OnConnect(const AAFwk::Want &want)
56 {
57 HILOG_INFO("CallLogAbility %{public}s begin.", __func__);
58 Extension::OnConnect(want);
59 sptr<DataShare::ContactsDataShareStubImpl> remoteObject =
60 new (std::nothrow) DataShare::ContactsDataShareStubImpl();
61 if (remoteObject == nullptr) {
62 HILOG_ERROR("%{public}s No memory allocated for DataShareStubImpl", __func__);
63 return nullptr;
64 }
65 remoteObject->SetCallLogAbility(std::static_pointer_cast<CallLogAbility>(shared_from_this()));
66 HILOG_INFO("CallLogAbility %{public}s end.", __func__);
67 return remoteObject->AsObject();
68 }
69
OnStart(const Want & want)70 void CallLogAbility::OnStart(const Want &want)
71 {
72 HILOG_INFO("CallLogAbility %{public}s begin.", __func__);
73 Extension::OnStart(want);
74 auto context = AbilityRuntime::Context::GetApplicationContext();
75 if (context != nullptr) {
76 context->SwitchArea(0);
77 std::string basePath = context->GetDatabaseDir();
78 Contacts::ContactsPath::RDB_PATH = basePath + "/";
79 Contacts::ContactsPath::RDB_BACKUP_PATH = basePath + "/backup/";
80 }
81 }
82
UriParse(Uri & uri)83 int CallLogAbility::UriParse(Uri &uri)
84 {
85 Contacts::UriUtils uriUtils;
86 int parseCode = uriUtils.UriParse(uri, uriValueMap_);
87 return parseCode;
88 }
89
90 /**
91 * @brief CallLogAbility BeginTransaction emptiness problems
92 *
93 * @param code the return number of BeginTransaction
94 * @param mutex transmission parameter : lock
95 *
96 * @return BeginTransaction emptiness true or false
97 */
IsBeginTransactionOK(int code,std::mutex & mutex)98 bool CallLogAbility::IsBeginTransactionOK(int code, std::mutex &mutex)
99 {
100 mutex.try_lock();
101 if (code != 0) {
102 HILOG_ERROR("IsBeginTransactionOK fail");
103 mutex.unlock();
104 return false;
105 }
106 return true;
107 }
108
109 /**
110 * @brief CallLogAbility Commit emptiness problems
111 *
112 * @param code the return number of Commit
113 * @param mutex transmission parameter : lock
114 *
115 * @return Commit emptiness true or false
116 */
IsCommitOk(int code,std::mutex & mutex)117 bool CallLogAbility::IsCommitOk(int code, std::mutex &mutex)
118 {
119 mutex.try_lock();
120 if (code != 0) {
121 HILOG_ERROR("IsCommitOk fail");
122 mutex.unlock();
123 return false;
124 }
125 return true;
126 }
127
128 /**
129 * @brief CallLogAbility Insert database
130 *
131 * @param uri Determine the data table name based on the URI
132 * @param value Insert the data value of the database
133 *
134 * @return Insert database results code
135 */
Insert(const Uri & uri,const DataShare::DataShareValuesBucket & value)136 int CallLogAbility::Insert(const Uri &uri, const DataShare::DataShareValuesBucket &value)
137 {
138 if (!Telephony::TelephonyPermission::CheckPermission(Telephony::Permission::WRITE_CALL_LOG)) {
139 HILOG_ERROR("Permission denied!");
140 return Contacts::RDB_PERMISSION_ERROR;
141 }
142 OHOS::NativeRdb::ValuesBucket valuesBucket = RdbDataShareAdapter::RdbUtils::ToValuesBucket(value);
143 Contacts::SqlAnalyzer sqlAnalyzer;
144 bool isOk = sqlAnalyzer.CheckValuesBucket(valuesBucket);
145 if (!isOk) {
146 HILOG_ERROR("CallLogAbility CheckValuesBucket is error");
147 return Contacts::RDB_EXECUTE_FAIL;
148 }
149 g_mutex.lock();
150 callLogDataBase_ = Contacts::CallLogDataBase::GetInstance();
151 int ret = callLogDataBase_->BeginTransaction();
152 if (!IsBeginTransactionOK(ret, g_mutex)) {
153 g_mutex.unlock();
154 return Contacts::RDB_EXECUTE_FAIL;
155 }
156 int resultId = InsertExecute(uri, valuesBucket);
157 if (resultId == Contacts::OPERATION_ERROR) {
158 callLogDataBase_->RollBack();
159 g_mutex.unlock();
160 return Contacts::OPERATION_ERROR;
161 }
162 ret = callLogDataBase_->Commit();
163 if (!IsCommitOk(ret, g_mutex)) {
164 callLogDataBase_->RollBack();
165 g_mutex.unlock();
166 return Contacts::RDB_EXECUTE_FAIL;
167 }
168 g_mutex.unlock();
169 DataBaseNotifyChange(Contacts::CONTACT_INSERT, uri);
170 return resultId;
171 }
172
InsertExecute(const Uri & uri,const OHOS::NativeRdb::ValuesBucket & value)173 int CallLogAbility::InsertExecute(const Uri &uri, const OHOS::NativeRdb::ValuesBucket &value)
174 {
175 int rowId = Contacts::RDB_EXECUTE_FAIL;
176 OHOS::Uri uriTemp = uri;
177 int parseCode = UriParse(uriTemp);
178 switch (parseCode) {
179 case Contacts::CALLLOG:
180 rowId = callLogDataBase_->InsertCallLog(value);
181 break;
182 default:
183 HILOG_ERROR("CallLogAbility ====>no match uri action");
184 break;
185 }
186 return rowId;
187 }
188
189 /**
190 * @brief CallLogAbility BatchInsert database
191 *
192 * @param uri Determine the data table name based on the URI
193 * @param value Insert the data values of the database
194 *
195 * @return Insert database results code
196 */
BatchInsert(const Uri & uri,const std::vector<DataShare::DataShareValuesBucket> & values)197 int CallLogAbility::BatchInsert(const Uri &uri, const std::vector<DataShare::DataShareValuesBucket> &values)
198 {
199 if (!Telephony::TelephonyPermission::CheckPermission(Telephony::Permission::WRITE_CALL_LOG)) {
200 HILOG_ERROR("Permission denied!");
201 return Contacts::RDB_PERMISSION_ERROR;
202 }
203 int rowRet = Contacts::RDB_EXECUTE_FAIL;
204 unsigned int size = values.size();
205 if (size < 1) {
206 HILOG_ERROR("BatchInsert value is error");
207 return rowRet;
208 }
209 g_mutex.lock();
210 callLogDataBase_ = Contacts::CallLogDataBase::GetInstance();
211 int ret = callLogDataBase_->BeginTransaction();
212 if (!IsBeginTransactionOK(ret, g_mutex)) {
213 g_mutex.unlock();
214 return Contacts::RDB_EXECUTE_FAIL;
215 }
216 int count = 0;
217 for (unsigned int i = 0; i < size; i++) {
218 ++count;
219 DataShare::DataShareValuesBucket rawContactValues = values[i];
220 OHOS::NativeRdb::ValuesBucket value = RdbDataShareAdapter::RdbUtils::ToValuesBucket(rawContactValues);
221 int code = InsertExecute(uri, value);
222 if (code == Contacts::RDB_EXECUTE_FAIL) {
223 callLogDataBase_->RollBack();
224 g_mutex.unlock();
225 return code;
226 }
227 if (count % Contacts::BATCH_INSERT_COUNT == 0) {
228 int markRet = callLogDataBase_->Commit();
229 int beginRet = callLogDataBase_->BeginTransaction();
230 if (!IsCommitOk(markRet, g_mutex) || !IsBeginTransactionOK(beginRet, g_mutex)) {
231 callLogDataBase_->RollBack();
232 g_mutex.unlock();
233 return Contacts::RDB_EXECUTE_FAIL;
234 }
235 }
236 }
237 int markRet = callLogDataBase_->Commit();
238 if (!IsCommitOk(markRet, g_mutex)) {
239 callLogDataBase_->RollBack();
240 g_mutex.unlock();
241 return Contacts::RDB_EXECUTE_FAIL;
242 }
243 g_mutex.unlock();
244 DataBaseNotifyChange(Contacts::CONTACT_INSERT, uri);
245 return Contacts::RDB_EXECUTE_OK;
246 }
247
248 /**
249 * @brief CallLogAbility Update database
250 *
251 * @param uri Determine the data table name based on the URI
252 * @param predicates Update the data value of the condition
253 *
254 * @return Update database results code
255 */
Update(const Uri & uri,const DataShare::DataSharePredicates & predicates,const DataShare::DataShareValuesBucket & value)256 int CallLogAbility::Update(
257 const Uri &uri, const DataShare::DataSharePredicates &predicates, const DataShare::DataShareValuesBucket &value)
258 {
259 if (!Telephony::TelephonyPermission::CheckPermission(Telephony::Permission::WRITE_CALL_LOG)) {
260 HILOG_ERROR("Permission denied!");
261 return Contacts::RDB_PERMISSION_ERROR;
262 }
263 OHOS::NativeRdb::ValuesBucket valuesBucket = RdbDataShareAdapter::RdbUtils::ToValuesBucket(value);
264 Contacts::SqlAnalyzer sqlAnalyzer;
265 bool isOk = sqlAnalyzer.CheckValuesBucket(valuesBucket);
266 if (!isOk) {
267 HILOG_ERROR("CallLogAbility CheckValuesBucket is error");
268 return Contacts::RDB_EXECUTE_FAIL;
269 }
270 g_mutex.lock();
271 callLogDataBase_ = Contacts::CallLogDataBase::GetInstance();
272 Contacts::PredicatesConvert predicatesConvert;
273 int ret = Contacts::RDB_EXECUTE_FAIL;
274 OHOS::Uri uriTemp = uri;
275 int parseCode = UriParse(uriTemp);
276 DataShare::DataSharePredicates dataSharePredicates = predicates;
277 OHOS::NativeRdb::RdbPredicates rdbPredicates("");
278 switch (parseCode) {
279 case Contacts::CALLLOG:
280 rdbPredicates =
281 predicatesConvert.ConvertPredicates(Contacts::CallsTableName::CALLLOG, dataSharePredicates);
282 ret = callLogDataBase_->UpdateCallLog(valuesBucket, rdbPredicates);
283 break;
284 default:
285 HILOG_ERROR("CallLogAbility ====>no match uri action");
286 break;
287 }
288 g_mutex.unlock();
289 DataBaseNotifyChange(Contacts::CONTACT_UPDATE, uri);
290 return ret;
291 }
292
293 /**
294 * @brief CallLogAbility Delete database
295 *
296 * @param uri Determine the data table name based on the URI
297 * @param predicates Delete the data values of the condition
298 *
299 * @return Delete database results code
300 */
Delete(const Uri & uri,const DataShare::DataSharePredicates & predicates)301 int CallLogAbility::Delete(const Uri &uri, const DataShare::DataSharePredicates &predicates)
302 {
303 if (!Telephony::TelephonyPermission::CheckPermission(Telephony::Permission::WRITE_CALL_LOG)) {
304 HILOG_ERROR("Permission denied!");
305 return Contacts::RDB_PERMISSION_ERROR;
306 }
307 g_mutex.lock();
308 callLogDataBase_ = Contacts::CallLogDataBase::GetInstance();
309 Contacts::PredicatesConvert predicatesConvert;
310 int ret = Contacts::RDB_EXECUTE_FAIL;
311 OHOS::Uri uriTemp = uri;
312 int parseCode = UriParse(uriTemp);
313 DataShare::DataSharePredicates dataSharePredicates = predicates;
314 OHOS::NativeRdb::RdbPredicates rdbPredicates("");
315 switch (parseCode) {
316 case Contacts::CALLLOG:
317 rdbPredicates =
318 predicatesConvert.ConvertPredicates(Contacts::CallsTableName::CALLLOG, dataSharePredicates);
319 ret = callLogDataBase_->DeleteCallLog(rdbPredicates);
320 break;
321 default:
322 HILOG_ERROR("CallLogAbility ====>no match uri action");
323 break;
324 }
325 g_mutex.unlock();
326 DataBaseNotifyChange(Contacts::CONTACT_DELETE, uri);
327 return ret;
328 }
329
330 /**
331 * @brief CallLogAbility Query database
332 *
333 * @param uri Determine the data table name based on the URI
334 * @param columns Columns returned by query
335 * @param predicates Query the data values of the condition
336 *
337 * @return Query database results
338 */
Query(const Uri & uri,const DataShare::DataSharePredicates & predicates,std::vector<std::string> & columns,DataShare::DatashareBusinessError & businessError)339 std::shared_ptr<DataShare::DataShareResultSet> CallLogAbility::Query(const Uri &uri,
340 const DataShare::DataSharePredicates &predicates, std::vector<std::string> &columns,
341 DataShare::DatashareBusinessError &businessError)
342 {
343 if (!Telephony::TelephonyPermission::CheckPermission(Telephony::Permission::READ_CALL_LOG)) {
344 HILOG_ERROR("Permission denied!");
345 return nullptr;
346 }
347 HILOG_INFO("CallLogAbility ====>Query start");
348 g_mutex.lock();
349 callLogDataBase_ = Contacts::CallLogDataBase::GetInstance();
350 if (callLogDataBase_ == nullptr) {
351 HILOG_ERROR("AbsSharedResultSet is nullptr");
352 return nullptr;
353 }
354 Contacts::PredicatesConvert predicatesConvert;
355 std::shared_ptr<OHOS::NativeRdb::ResultSet> result;
356 OHOS::Uri uriTemp = uri;
357 Contacts::UriUtils uriUtils;
358 int parseCode = uriUtils.UriParse(uriTemp, uriValueMap_);
359 HILOG_INFO("CallLogAbility ====>Query parseCode");
360 DataShare::DataSharePredicates dataSharePredicates = predicates;
361 OHOS::NativeRdb::RdbPredicates rdbPredicates("");
362 std::vector<std::string> columnsTemp = columns;
363 bool isUriMatch = true;
364 switch (parseCode) {
365 case Contacts::CALLLOG:
366 rdbPredicates =
367 predicatesConvert.ConvertPredicates(Contacts::CallsTableName::CALLLOG, dataSharePredicates);
368 result = callLogDataBase_->Query(rdbPredicates, columnsTemp);
369 break;
370 default:
371 isUriMatch = false;
372 HILOG_ERROR("CallLogAbility ====>no match uri action");
373 break;
374 }
375 if (!isUriMatch) {
376 g_mutex.unlock();
377 return nullptr;
378 }
379 if (result == nullptr) {
380 HILOG_ERROR("AbsSharedResultSet is nullptr");
381 g_mutex.unlock();
382 return nullptr;
383 }
384 auto queryResultSet = RdbDataShareAdapter::RdbUtils::ToResultSetBridge(result);
385 std::shared_ptr<DataShare::DataShareResultSet> sharedPtrResult =
386 std::make_shared<DataShare::DataShareResultSet>(queryResultSet);
387 g_mutex.unlock();
388 HILOG_INFO("CallLogAbility ====>Query end");
389 return sharedPtrResult;
390 }
391
DataBaseNotifyChange(int code,Uri uri)392 void CallLogAbility::DataBaseNotifyChange(int code, Uri uri)
393 {
394 Contacts::ContactsCommonEvent::SendCallLogChange(code);
395 }
396 } // namespace AbilityRuntime
397 } // namespace OHOS
398