1 /*
2 * Copyright (C) 2024 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 #define MLOG_TAG "DataManager"
17
18 #include "ringtone_data_manager.h"
19
20 #include "directory_ex.h"
21 #include "rdb_utils.h"
22 #include "ringtone_fetch_result.h"
23 #include "ringtone_file_utils.h"
24 #include "ringtone_log.h"
25 #include "ringtone_mimetype_utils.h"
26 #include "ringtone_rdbstore.h"
27 #include "ringtone_scanner_manager.h"
28 #include "ringtone_tracer.h"
29 #include "ringtone_xcollie.h"
30 #include "ringtone_utils.h"
31
32 namespace OHOS {
33 namespace Media {
34 using namespace std;
35 using namespace OHOS::AppExecFwk;
36 using namespace OHOS::AbilityRuntime;
37 using namespace OHOS::NativeRdb;
38 using namespace OHOS::DataShare;
39 using namespace OHOS::RdbDataShareAdapter;
40 shared_ptr<RingtoneDataManager> RingtoneDataManager::instance_ = nullptr;
41 mutex RingtoneDataManager::mutex_;
42 shared_ptr<RingtoneUnistore> g_uniStore = nullptr;
43
RingtoneDataManager(void)44 RingtoneDataManager::RingtoneDataManager(void)
45 {
46 }
47
~RingtoneDataManager(void)48 RingtoneDataManager::~RingtoneDataManager(void)
49 {
50 }
51
GetInstance()52 shared_ptr<RingtoneDataManager> RingtoneDataManager::GetInstance()
53 {
54 if (instance_ == nullptr) {
55 lock_guard<mutex> lock(mutex_);
56
57 if (instance_ == nullptr) {
58 instance_ = make_shared<RingtoneDataManager>();
59 }
60 }
61 return instance_;
62 }
63
Init(const shared_ptr<OHOS::AbilityRuntime::Context> & context)64 int32_t RingtoneDataManager::Init(const shared_ptr<OHOS::AbilityRuntime::Context> &context)
65 {
66 RINGTONE_DEBUG_LOG("start");
67 lock_guard<shared_mutex> lock(mgrSharedMutex_);
68
69 if (refCnt_.load() > 0) {
70 RINGTONE_DEBUG_LOG("already initialized");
71 refCnt_++;
72 return E_OK;
73 }
74 context_ = context;
75 if (g_uniStore == nullptr) {
76 g_uniStore = RingtoneRdbStore::GetInstance(context_);
77 if (g_uniStore == nullptr) {
78 RINGTONE_ERR_LOG("RingtoneDataManager is not initialized");
79 return E_DB_FAIL;
80 }
81 }
82 RingtoneMimeTypeUtils::InitMimeTypeMap();
83 refCnt_++;
84
85 RINGTONE_DEBUG_LOG("end");
86 return E_OK;
87 }
88
DeleteRingtoneRowById(int32_t toneId)89 int32_t RingtoneDataManager::DeleteRingtoneRowById(int32_t toneId)
90 {
91 const string DELETE_SELECTION = RINGTONE_COLUMN_TONE_ID + " = ? ";
92 Uri uri(RINGTONE_PATH_URI);
93 RingtoneDataCommand cmd(uri, RINGTONE_TABLE, RingtoneOperationType::DELETE);
94 DataSharePredicates predicates;
95 vector<string> selectionArgs = { to_string(toneId) };
96 predicates.SetWhereClause(DELETE_SELECTION);
97 predicates.SetWhereArgs(selectionArgs);
98
99 return this->Delete(cmd, predicates, true);
100 }
101
Insert(RingtoneDataCommand & cmd,const DataShareValuesBucket & dataShareValue)102 int32_t RingtoneDataManager::Insert(RingtoneDataCommand &cmd, const DataShareValuesBucket &dataShareValue)
103 {
104 RINGTONE_DEBUG_LOG("start");
105 shared_lock<shared_mutex> sharedLock(mgrSharedMutex_);
106 if (refCnt_.load() <= 0) {
107 RINGTONE_ERR_LOG("RingtoneDataManager is not initialized");
108 return E_FAIL;
109 }
110 if (g_uniStore == nullptr) {
111 RINGTONE_ERR_LOG("rdb store is not initialized");
112 return E_DB_FAIL;
113 }
114
115 ValuesBucket value = RdbUtils::ToValuesBucket(dataShareValue);
116 if (value.IsEmpty()) {
117 RINGTONE_ERR_LOG("RingtoneDataManager Insert: Input parameter is invalid");
118 return E_INVALID_VALUES;
119 }
120 cmd.SetValueBucket(value);
121 int32_t err = CheckVideoRingtoneSize(cmd, dataShareValue);
122 CHECK_AND_RETURN_RET_LOG(err == E_SUCCESS, err,
123 "Check video ringtone size failed, errCode: %{public}d", err);
124
125 int64_t outRowId = E_HAS_DB_ERROR;
126 auto retRdb = g_uniStore->Insert(cmd, outRowId);
127 if (retRdb != NativeRdb::E_OK) {
128 RINGTONE_ERR_LOG("Insert operation failed. Result %{public}d.", retRdb);
129 return E_HAS_DB_ERROR;
130 }
131 if (cmd.GetTableName().compare(SIMCARD_SETTING_TABLE) == 0) {
132 return static_cast<int32_t>(outRowId);
133 }
134
135 auto asset = GetRingtoneAssetFromId(to_string(outRowId));
136 if (asset == nullptr) {
137 int32_t deleteRet = DeleteRingtoneRowById(outRowId);
138 RINGTONE_ERR_LOG("Failed to get RingtoneAsset, delete row %{public}d from db, return %{public}d",
139 static_cast<int32_t>(outRowId), deleteRet);
140 return E_INVALID_VALUES;
141 }
142
143 auto ret = RingtoneFileUtils::CreateFile(asset->GetPath());
144 if (ret != E_SUCCESS) {
145 int32_t deleteRet = DeleteRingtoneRowById(outRowId);
146 RINGTONE_ERR_LOG("Failed to create file, delete row %{public}d from db, return %{public}d",
147 static_cast<int32_t>(outRowId), deleteRet);
148 return ret;
149 }
150
151 RINGTONE_DEBUG_LOG("end");
152 return static_cast<int32_t>(outRowId);
153 }
154
DeleteFileFromResultSet(std::shared_ptr<NativeRdb::ResultSet> & resultSet)155 int32_t RingtoneDataManager::DeleteFileFromResultSet(std::shared_ptr<NativeRdb::ResultSet> &resultSet)
156 {
157 auto count = 0;
158 if (resultSet == nullptr) {
159 RINGTONE_ERR_LOG("resultSet is nullptr");
160 return E_ERR;
161 }
162 auto ret = resultSet->GetRowCount(count);
163 if (ret != NativeRdb::E_OK) {
164 RINGTONE_ERR_LOG("get rdbstore failed");
165 return E_HAS_DB_ERROR;
166 }
167 if (count == 0) {
168 RINGTONE_ERR_LOG("have no files to delete");
169 return E_SUCCESS;
170 }
171
172 shared_ptr<RingtoneFetchResult<RingtoneAsset>> fetchResult = make_shared<RingtoneFetchResult<RingtoneAsset>>();
173 if (fetchResult == nullptr) {
174 RINGTONE_ERR_LOG("Failed to obtain fetch file result");
175 return E_ERR;
176 }
177
178 for (auto i = 0; i < count; i++) {
179 auto asset = fetchResult->GetObjectFromRdb(resultSet, i);
180 if (asset == nullptr) {
181 RINGTONE_ERR_LOG("asset is nullptr");
182 continue;
183 }
184 RingtoneFileUtils::DeleteFile(asset->GetPath());
185 }
186
187 return E_SUCCESS;
188 }
189
Delete(RingtoneDataCommand & cmd,const DataSharePredicates & predicates,bool onlyDb)190 int32_t RingtoneDataManager::Delete(RingtoneDataCommand &cmd, const DataSharePredicates &predicates, bool onlyDb)
191 {
192 RINGTONE_DEBUG_LOG("start");
193 shared_lock<shared_mutex> sharedLock(mgrSharedMutex_);
194 if (refCnt_.load() <= 0) {
195 RINGTONE_DEBUG_LOG("RingtoneDataManager is not initialized");
196 return E_FAIL;
197 }
198 if (g_uniStore == nullptr) {
199 RINGTONE_ERR_LOG("rdb store is not initialized");
200 return E_DB_FAIL;
201 }
202
203 NativeRdb::RdbPredicates rdbPredicate = RdbUtils::ToPredicates(predicates, cmd.GetTableName());
204 cmd.GetAbsRdbPredicates()->SetWhereClause(rdbPredicate.GetWhereClause());
205 cmd.GetAbsRdbPredicates()->SetWhereArgs(rdbPredicate.GetWhereArgs());
206
207 if (cmd.GetTableName().compare(SIMCARD_SETTING_TABLE) == 0) {
208 onlyDb = true;
209 } else {
210 vector<string> columns = {RINGTONE_COLUMN_TONE_ID, RINGTONE_COLUMN_DATA};
211 auto absResultSet = g_uniStore->Query(cmd, columns);
212 if (!onlyDb) {
213 DeleteFileFromResultSet(absResultSet);
214 }
215 }
216
217 int32_t deletedRows = E_HAS_DB_ERROR;
218 int32_t ret = g_uniStore->Delete(cmd, deletedRows);
219 if (ret != NativeRdb::E_OK || deletedRows <= 0) {
220 RINGTONE_ERR_LOG("Delete operation failed. Result %{public}d.", ret);
221 deletedRows = E_HAS_DB_ERROR;
222 }
223
224 RINGTONE_DEBUG_LOG("end");
225 return deletedRows;
226 }
227
Update(RingtoneDataCommand & cmd,const DataShareValuesBucket & dataShareValue,const DataSharePredicates & predicates)228 int32_t RingtoneDataManager::Update(RingtoneDataCommand &cmd, const DataShareValuesBucket &dataShareValue,
229 const DataSharePredicates &predicates)
230 {
231 RINGTONE_DEBUG_LOG("start");
232 shared_lock<shared_mutex> sharedLock(mgrSharedMutex_);
233 if (refCnt_.load() <= 0) {
234 RINGTONE_DEBUG_LOG("RingtoneDataManager is not initialized");
235 return E_FAIL;
236 }
237 if (g_uniStore == nullptr) {
238 RINGTONE_ERR_LOG("rdb store is not initialized");
239 return E_DB_FAIL;
240 }
241
242 ValuesBucket value = RdbUtils::ToValuesBucket(dataShareValue);
243 if (value.IsEmpty()) {
244 RINGTONE_ERR_LOG("RingtoneDataManager Update:Input parameter is invalid");
245 return E_INVALID_VALUES;
246 }
247
248 cmd.SetValueBucket(value);
249 cmd.SetDataSharePred(predicates);
250 NativeRdb::RdbPredicates rdbPredicate = RdbUtils::ToPredicates(predicates, cmd.GetTableName());
251 cmd.GetAbsRdbPredicates()->SetWhereClause(rdbPredicate.GetWhereClause());
252 cmd.GetAbsRdbPredicates()->SetWhereArgs(rdbPredicate.GetWhereArgs());
253
254 int32_t updatedRows = E_HAS_DB_ERROR;
255 int32_t result = g_uniStore->Update(cmd, updatedRows);
256 if (result != NativeRdb::E_OK || updatedRows <= 0) {
257 RINGTONE_ERR_LOG("Update operation failed. Result %{public}d. Updated %{public}d", result, updatedRows);
258 updatedRows = E_HAS_DB_ERROR;
259 }
260
261 RINGTONE_DEBUG_LOG("end");
262 return updatedRows;
263 }
264
Query(RingtoneDataCommand & cmd,const vector<string> & columns,const DataSharePredicates & predicates,int & errCode)265 shared_ptr<ResultSetBridge> RingtoneDataManager::Query(RingtoneDataCommand &cmd,
266 const vector<string> &columns, const DataSharePredicates &predicates, int &errCode)
267 {
268 RINGTONE_DEBUG_LOG("start");
269 shared_lock<shared_mutex> sharedLock(mgrSharedMutex_);
270 if (refCnt_.load() <= 0) {
271 RINGTONE_DEBUG_LOG("RingtoneDataManager is not initialized");
272 return nullptr;
273 }
274 if (g_uniStore == nullptr) {
275 RINGTONE_ERR_LOG("rdb store is not initialized");
276 return nullptr;
277 }
278
279 RingtoneTracer tracer;
280 tracer.Start("RingtoneDataManager::Query");
281 cmd.SetDataSharePred(predicates);
282 NativeRdb::RdbPredicates rdbPredicate = RdbUtils::ToPredicates(predicates, cmd.GetTableName());
283 cmd.GetAbsRdbPredicates()->SetWhereClause(rdbPredicate.GetWhereClause());
284 cmd.GetAbsRdbPredicates()->SetWhereArgs(rdbPredicate.GetWhereArgs());
285 cmd.GetAbsRdbPredicates()->SetOrder(rdbPredicate.GetOrder());
286 cmd.GetAbsRdbPredicates()->SetJoinConditions(rdbPredicate.GetJoinConditions());
287 cmd.GetAbsRdbPredicates()->SetJoinTableNames(rdbPredicate.GetJoinTableNames());
288 cmd.GetAbsRdbPredicates()->SetJoinTypes(rdbPredicate.GetJoinTypes());
289
290 auto absResultSet = g_uniStore->Query(cmd, columns);
291
292 RINGTONE_DEBUG_LOG("end");
293 return RdbUtils::ToResultSetBridge(absResultSet);
294 }
295
OpenRingtoneFile(RingtoneDataCommand & cmd,const string & mode)296 int32_t RingtoneDataManager::OpenRingtoneFile(RingtoneDataCommand &cmd, const string &mode)
297 {
298 RINGTONE_DEBUG_LOG("start");
299 RingtoneTracer tracer;
300 tracer.Start("RingtoneDataManager::OpenFile");
301 string toneId = GetIdFromUri(const_cast<Uri &>(cmd.GetUri()), RINGTONE_URI_PATH);
302 auto asset = GetRingtoneAssetFromId(toneId);
303 if (asset == nullptr) {
304 RINGTONE_ERR_LOG("Failed to get RingtoneAsset");
305 return E_INVALID_VALUES;
306 }
307 if (access(asset->GetPath().c_str(), F_OK) != E_OK) {
308 RINGTONE_ERR_LOG("File not exist: %{public}s", asset->GetPath().c_str());
309 return E_ERR;
310 }
311 string absFilePath;
312 RingtoneXCollie ringtoneXCollie("RingtoneFile PathToRealPath time out",
313 [](void *) {
314 RINGTONE_INFO_LOG("RingtoneFile PathToRealPath time out");
315 });
316 if (!PathToRealPath(asset->GetPath(), absFilePath)) {
317 RINGTONE_ERR_LOG("Failed to get real path: %{private}s, err:%{public}d", asset->GetPath().c_str(), errno);
318 ringtoneXCollie.CancelXCollieTimer();
319 return E_ERR;
320 }
321 ringtoneXCollie.CancelXCollieTimer();
322
323 RINGTONE_DEBUG_LOG("end");
324 return RingtoneFileUtils::OpenFile(absFilePath, mode);
325 }
326
OpenVibrateFile(RingtoneDataCommand & cmd,const string & mode)327 int32_t RingtoneDataManager::OpenVibrateFile(RingtoneDataCommand &cmd, const string &mode)
328 {
329 RINGTONE_DEBUG_LOG("start");
330 RingtoneTracer tracer;
331 tracer.Start("RingtoneDataManager::OpenFile");
332 string toneId = GetIdFromUri(const_cast<Uri &>(cmd.GetUri()), VIBRATE_URI_PATH);
333 auto asset = GetVibrateAssetFromId(toneId);
334 if (asset == nullptr) {
335 RINGTONE_ERR_LOG("Failed to get VibrateAsset");
336 return E_INVALID_VALUES;
337 }
338
339 string absFilePath;
340 RingtoneXCollie ringtoneXCollie("VibrateFile PathToRealPath time out",
341 [](void *) {
342 RINGTONE_INFO_LOG("VibrateFile PathToRealPath time out");
343 });
344 if (!PathToRealPath(asset->GetPath(), absFilePath)) {
345 RINGTONE_ERR_LOG("Failed to get real path: %{private}s", asset->GetPath().c_str());
346 ringtoneXCollie.CancelXCollieTimer();
347 return E_ERR;
348 }
349 ringtoneXCollie.CancelXCollieTimer();
350 RINGTONE_DEBUG_LOG("end");
351 return RingtoneFileUtils::OpenVibrateFile(absFilePath, mode);
352 }
353
OpenFile(RingtoneDataCommand & cmd,const string & mode)354 int32_t RingtoneDataManager::OpenFile(RingtoneDataCommand &cmd, const string &mode)
355 {
356 RINGTONE_INFO_LOG("openfile uri %{public}s", cmd.GetUri().ToString().c_str());
357 RINGTONE_INFO_LOG("openfile table %{public}s", cmd.GetTableName().c_str());
358 if (cmd.GetTableName() == RINGTONE_TABLE) {
359 return OpenRingtoneFile(cmd, mode);
360 } else {
361 return OpenVibrateFile(cmd, mode);
362 }
363 }
364
SetOwner(const shared_ptr<RingtoneDataShareExtension> & datashareExternsion)365 void RingtoneDataManager::SetOwner(const shared_ptr<RingtoneDataShareExtension> &datashareExternsion)
366 {
367 extension_ = datashareExternsion;
368 }
369
GetOwner()370 shared_ptr<RingtoneDataShareExtension> RingtoneDataManager::GetOwner()
371 {
372 return extension_;
373 }
374
GetIdFromUri(Uri & uri,const std::string & uriPath)375 string RingtoneDataManager::GetIdFromUri(Uri &uri, const std::string &uriPath)
376 {
377 vector<string> segments;
378 uri.GetPathSegments(segments);
379 const int uriSegmentsCount = 3;
380 const int toneIdSegmentNumber = 2;
381 if (segments.size() != uriSegmentsCount || segments[1] != uriPath ||
382 !RingtoneUtils::IsNumber(segments[toneIdSegmentNumber])) {
383 return {};
384 }
385 return segments[toneIdSegmentNumber];
386 }
387
GetRingtoneAssetFromId(const string & id)388 shared_ptr<RingtoneAsset> RingtoneDataManager::GetRingtoneAssetFromId(const string &id)
389 {
390 if ((id.empty()) || (!RingtoneUtils::IsNumber(id))) {
391 RINGTONE_ERR_LOG("Id for the path is incorrect: %{private}s", id.c_str());
392 return nullptr;
393 }
394 Uri uri("");
395 RingtoneDataCommand cmd(uri, RINGTONE_TABLE, RingtoneOperationType::QUERY);
396 cmd.GetAbsRdbPredicates()->EqualTo(RINGTONE_COLUMN_TONE_ID, id);
397
398 auto resultSet = g_uniStore->Query(cmd, {RINGTONE_COLUMN_TONE_ID, RINGTONE_COLUMN_DATA});
399 if (resultSet == nullptr) {
400 RINGTONE_ERR_LOG("Failed to obtain file asset from database");
401 return nullptr;
402 }
403
404 shared_ptr<RingtoneFetchResult<RingtoneAsset>> fetchResult = make_shared<RingtoneFetchResult<RingtoneAsset>>();
405 if (fetchResult == nullptr) {
406 RINGTONE_ERR_LOG("Failed to obtain fetch file result");
407 return nullptr;
408 }
409 return fetchResult->GetObjectFromRdb(resultSet, 0);
410 }
411
GetVibrateAssetFromId(const std::string & id)412 std::shared_ptr<VibrateAsset> RingtoneDataManager::GetVibrateAssetFromId(const std::string &id)
413 {
414 if ((id.empty()) || (!RingtoneUtils::IsNumber(id))) {
415 RINGTONE_ERR_LOG("Id for the path is incorrect: %{private}s", id.c_str());
416 return nullptr;
417 }
418 Uri uri("");
419 RingtoneDataCommand cmd(uri, VIBRATE_TABLE, RingtoneOperationType::QUERY);
420 cmd.GetAbsRdbPredicates()->EqualTo(VIBRATE_COLUMN_VIBRATE_ID, id);
421
422 auto resultSet = g_uniStore->Query(cmd, {VIBRATE_COLUMN_VIBRATE_ID, VIBRATE_COLUMN_DATA});
423 if (resultSet == nullptr) {
424 RINGTONE_ERR_LOG("Failed to obtain file asset from database");
425 return nullptr;
426 }
427
428 shared_ptr<RingtoneFetchResult<VibrateAsset>> fetchResult = make_shared<RingtoneFetchResult<VibrateAsset>>();
429 if (fetchResult == nullptr) {
430 RINGTONE_ERR_LOG("Failed to obtain fetch file result");
431 return nullptr;
432 }
433 return fetchResult->GetObjectFromRdb(resultSet, 0);
434 }
435
ClearRingtoneDataMgr()436 void RingtoneDataManager::ClearRingtoneDataMgr()
437 {
438 lock_guard<shared_mutex> lock(mgrSharedMutex_);
439
440 refCnt_--;
441 if (refCnt_.load() > 0) {
442 RINGTONE_DEBUG_LOG("still other extension exist");
443 return;
444 }
445
446 extension_ = nullptr;
447 }
448
CheckVideoRingtoneSize(RingtoneDataCommand & cmd,const DataShareValuesBucket & value)449 int32_t RingtoneDataManager::CheckVideoRingtoneSize(RingtoneDataCommand &cmd, const DataShareValuesBucket &value)
450 {
451 if (value.IsEmpty()) {
452 RINGTONE_ERR_LOG("CheckVideoRingtoneSize failed, value is empty");
453 return E_INVALID_VALUES;
454 }
455 if (cmd.GetTableName().compare(RINGTONE_TABLE) != 0) {
456 return E_OK;
457 }
458 bool isValid = false;
459 int32_t mediaType = value.Get(RINGTONE_COLUMN_MEDIA_TYPE, isValid);
460 if (!isValid) {
461 RINGTONE_ERR_LOG("CheckVideoRingtoneSize failed, media type is not valid");
462 return E_INVALID_VALUES;
463 }
464 if (mediaType == RINGTONE_MEDIA_TYPE_VIDEO) {
465 if (!RingtoneUtils::CheckRemainSpaceMeetCondition()) {
466 RINGTONE_ERR_LOG("CheckVideoRingtoneSize failed, not enough space");
467 return E_NOT_ENOUGH_ROM;
468 }
469 std::vector<std::string> columns = { "count(1) AS count" };
470 Uri uri("");
471 RingtoneDataCommand cmd(uri, RINGTONE_TABLE, RingtoneOperationType::QUERY);
472 cmd.GetAbsRdbPredicates()->EqualTo(RINGTONE_COLUMN_MEDIA_TYPE, RINGTONE_MEDIA_TYPE_VIDEO);
473 auto resultSet = g_uniStore->Query(cmd, columns);
474 if (resultSet == nullptr || resultSet->GoToFirstRow() != NativeRdb::E_OK) {
475 RINGTONE_ERR_LOG("Query video ringtone count failed");
476 return E_INVALID_VALUES;
477 }
478 int isIndex = -1;
479 int32_t num = 0;
480 resultSet->GetColumnIndex("count", isIndex);
481 resultSet->GetInt(isIndex, num);
482 resultSet->Close();
483 if (num >= RINGTONE_VIDEO_MAX_COUNT) {
484 RINGTONE_ERR_LOG("CheckVideoRingtoneSize failed, video ringtone count exceeds limit");
485 return E_VIDEOS_NUM_EXCEEDS_SPECIFICATION;
486 }
487 } else if (mediaType == RINGTONE_MEDIA_TYPE_AUDIO) {
488 return E_OK;
489 } else {
490 RINGTONE_ERR_LOG("CheckVideoRingtoneSize failed, media type is not video or audio");
491 return E_INVALID_VALUES;
492 }
493 return E_OK;
494 }
495 } // namespace Media
496 } // namespace OHOS
497