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
31 namespace OHOS {
32 namespace Media {
33 using namespace std;
34 using namespace OHOS::AppExecFwk;
35 using namespace OHOS::AbilityRuntime;
36 using namespace OHOS::NativeRdb;
37 using namespace OHOS::DataShare;
38 using namespace OHOS::RdbDataShareAdapter;
39 shared_ptr<RingtoneDataManager> RingtoneDataManager::instance_ = nullptr;
40 mutex RingtoneDataManager::mutex_;
41 shared_ptr<RingtoneUnistore> g_uniStore = nullptr;
42 constexpr int32_t MAX_SIZE = 9;
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
122 int64_t outRowId = E_HAS_DB_ERROR;
123 auto retRdb = g_uniStore->Insert(cmd, outRowId);
124 if (retRdb != NativeRdb::E_OK) {
125 RINGTONE_ERR_LOG("Insert operation failed. Result %{public}d.", retRdb);
126 return E_HAS_DB_ERROR;
127 }
128 if (cmd.GetTableName().compare(SIMCARD_SETTING_TABLE) == 0) {
129 return static_cast<int32_t>(outRowId);
130 }
131
132 auto asset = GetRingtoneAssetFromId(to_string(outRowId));
133 if (asset == nullptr) {
134 int32_t deleteRet = DeleteRingtoneRowById(outRowId);
135 RINGTONE_ERR_LOG("Failed to get RingtoneAsset, delete row %{public}d from db, return %{public}d",
136 static_cast<int32_t>(outRowId), deleteRet);
137 return E_INVALID_VALUES;
138 }
139
140 auto ret = RingtoneFileUtils::CreateFile(asset->GetPath());
141 if (ret != E_SUCCESS) {
142 int32_t deleteRet = DeleteRingtoneRowById(outRowId);
143 RINGTONE_ERR_LOG("Failed to create file, delete row %{public}d from db, return %{public}d",
144 static_cast<int32_t>(outRowId), deleteRet);
145 return ret;
146 }
147
148 RINGTONE_DEBUG_LOG("end");
149 return static_cast<int32_t>(outRowId);
150 }
151
DeleteFileFromResultSet(std::shared_ptr<NativeRdb::ResultSet> & resultSet)152 int32_t RingtoneDataManager::DeleteFileFromResultSet(std::shared_ptr<NativeRdb::ResultSet> &resultSet)
153 {
154 auto count = 0;
155 if (resultSet == nullptr) {
156 RINGTONE_ERR_LOG("resultSet is nullptr");
157 return E_ERR;
158 }
159 auto ret = resultSet->GetRowCount(count);
160 if (ret != NativeRdb::E_OK) {
161 RINGTONE_ERR_LOG("get rdbstore failed");
162 return E_HAS_DB_ERROR;
163 }
164 if (count == 0) {
165 RINGTONE_ERR_LOG("have no files to delete");
166 return E_SUCCESS;
167 }
168
169 shared_ptr<RingtoneFetchResult<RingtoneAsset>> fetchResult = make_shared<RingtoneFetchResult<RingtoneAsset>>();
170 if (fetchResult == nullptr) {
171 RINGTONE_ERR_LOG("Failed to obtain fetch file result");
172 return E_ERR;
173 }
174
175 for (auto i = 0; i < count; i++) {
176 auto asset = fetchResult->GetObjectFromRdb(resultSet, i);
177 if (asset == nullptr) {
178 RINGTONE_ERR_LOG("asset is nullptr");
179 continue;
180 }
181 RingtoneFileUtils::DeleteFile(asset->GetPath());
182 }
183
184 return E_SUCCESS;
185 }
186
Delete(RingtoneDataCommand & cmd,const DataSharePredicates & predicates,bool onlyDb)187 int32_t RingtoneDataManager::Delete(RingtoneDataCommand &cmd, const DataSharePredicates &predicates, bool onlyDb)
188 {
189 RINGTONE_DEBUG_LOG("start");
190 shared_lock<shared_mutex> sharedLock(mgrSharedMutex_);
191 if (refCnt_.load() <= 0) {
192 RINGTONE_DEBUG_LOG("RingtoneDataManager is not initialized");
193 return E_FAIL;
194 }
195 if (g_uniStore == nullptr) {
196 RINGTONE_ERR_LOG("rdb store is not initialized");
197 return E_DB_FAIL;
198 }
199
200 NativeRdb::RdbPredicates rdbPredicate = RdbUtils::ToPredicates(predicates, cmd.GetTableName());
201 cmd.GetAbsRdbPredicates()->SetWhereClause(rdbPredicate.GetWhereClause());
202 cmd.GetAbsRdbPredicates()->SetWhereArgs(rdbPredicate.GetWhereArgs());
203
204 if (cmd.GetTableName().compare(SIMCARD_SETTING_TABLE) == 0) {
205 onlyDb = true;
206 } else {
207 vector<string> columns = {RINGTONE_COLUMN_TONE_ID, RINGTONE_COLUMN_DATA};
208 auto absResultSet = g_uniStore->Query(cmd, columns);
209 if (!onlyDb) {
210 DeleteFileFromResultSet(absResultSet);
211 }
212 }
213
214 int32_t deletedRows = E_HAS_DB_ERROR;
215 int32_t ret = g_uniStore->Delete(cmd, deletedRows);
216 if (ret != NativeRdb::E_OK || deletedRows <= 0) {
217 RINGTONE_ERR_LOG("Delete operation failed. Result %{public}d.", ret);
218 deletedRows = E_HAS_DB_ERROR;
219 }
220
221 RINGTONE_DEBUG_LOG("end");
222 return deletedRows;
223 }
224
Update(RingtoneDataCommand & cmd,const DataShareValuesBucket & dataShareValue,const DataSharePredicates & predicates)225 int32_t RingtoneDataManager::Update(RingtoneDataCommand &cmd, const DataShareValuesBucket &dataShareValue,
226 const DataSharePredicates &predicates)
227 {
228 RINGTONE_DEBUG_LOG("start");
229 shared_lock<shared_mutex> sharedLock(mgrSharedMutex_);
230 if (refCnt_.load() <= 0) {
231 RINGTONE_DEBUG_LOG("RingtoneDataManager is not initialized");
232 return E_FAIL;
233 }
234 if (g_uniStore == nullptr) {
235 RINGTONE_ERR_LOG("rdb store is not initialized");
236 return E_DB_FAIL;
237 }
238
239 ValuesBucket value = RdbUtils::ToValuesBucket(dataShareValue);
240 if (value.IsEmpty()) {
241 RINGTONE_ERR_LOG("RingtoneDataManager Update:Input parameter is invalid");
242 return E_INVALID_VALUES;
243 }
244
245 cmd.SetValueBucket(value);
246 cmd.SetDataSharePred(predicates);
247 NativeRdb::RdbPredicates rdbPredicate = RdbUtils::ToPredicates(predicates, cmd.GetTableName());
248 cmd.GetAbsRdbPredicates()->SetWhereClause(rdbPredicate.GetWhereClause());
249 cmd.GetAbsRdbPredicates()->SetWhereArgs(rdbPredicate.GetWhereArgs());
250
251 int32_t updatedRows = E_HAS_DB_ERROR;
252 int32_t result = g_uniStore->Update(cmd, updatedRows);
253 if (result != NativeRdb::E_OK || updatedRows <= 0) {
254 RINGTONE_ERR_LOG("Update operation failed. Result %{public}d. Updated %{public}d", result, updatedRows);
255 updatedRows = E_HAS_DB_ERROR;
256 }
257
258 RINGTONE_DEBUG_LOG("end");
259 return updatedRows;
260 }
261
Query(RingtoneDataCommand & cmd,const vector<string> & columns,const DataSharePredicates & predicates,int & errCode)262 shared_ptr<ResultSetBridge> RingtoneDataManager::Query(RingtoneDataCommand &cmd,
263 const vector<string> &columns, const DataSharePredicates &predicates, int &errCode)
264 {
265 RINGTONE_DEBUG_LOG("start");
266 shared_lock<shared_mutex> sharedLock(mgrSharedMutex_);
267 if (refCnt_.load() <= 0) {
268 RINGTONE_DEBUG_LOG("RingtoneDataManager is not initialized");
269 return nullptr;
270 }
271 if (g_uniStore == nullptr) {
272 RINGTONE_ERR_LOG("rdb store is not initialized");
273 return nullptr;
274 }
275
276 RingtoneTracer tracer;
277 tracer.Start("RingtoneDataManager::Query");
278 cmd.SetDataSharePred(predicates);
279 NativeRdb::RdbPredicates rdbPredicate = RdbUtils::ToPredicates(predicates, cmd.GetTableName());
280 cmd.GetAbsRdbPredicates()->SetWhereClause(rdbPredicate.GetWhereClause());
281 cmd.GetAbsRdbPredicates()->SetWhereArgs(rdbPredicate.GetWhereArgs());
282 cmd.GetAbsRdbPredicates()->SetOrder(rdbPredicate.GetOrder());
283 cmd.GetAbsRdbPredicates()->SetJoinConditions(rdbPredicate.GetJoinConditions());
284 cmd.GetAbsRdbPredicates()->SetJoinTableNames(rdbPredicate.GetJoinTableNames());
285 cmd.GetAbsRdbPredicates()->SetJoinTypes(rdbPredicate.GetJoinTypes());
286
287 auto absResultSet = g_uniStore->Query(cmd, columns);
288
289 RINGTONE_DEBUG_LOG("end");
290 return RdbUtils::ToResultSetBridge(absResultSet);
291 }
292
IsNumber(const string & str)293 static bool IsNumber(const string &str)
294 {
295 if (str.empty()) {
296 RINGTONE_DEBUG_LOG("IsNumber input is empty ");
297 return false;
298 }
299 if (str.size() > MAX_SIZE) {
300 RINGTONE_ERR_LOG("IsNumber input is too long ");
301 return false;
302 }
303 for (char const &c : str) {
304 if (isdigit(c) == 0) {
305 return false;
306 }
307 }
308 return true;
309 }
310
OpenRingtoneFile(RingtoneDataCommand & cmd,const string & mode)311 int32_t RingtoneDataManager::OpenRingtoneFile(RingtoneDataCommand &cmd, const string &mode)
312 {
313 RINGTONE_DEBUG_LOG("start");
314 RingtoneTracer tracer;
315 tracer.Start("RingtoneDataManager::OpenFile");
316 string toneId = GetIdFromUri(const_cast<Uri &>(cmd.GetUri()), RINGTONE_URI_PATH);
317 auto asset = GetRingtoneAssetFromId(toneId);
318 if (asset == nullptr) {
319 RINGTONE_ERR_LOG("Failed to get RingtoneAsset");
320 return E_INVALID_VALUES;
321 }
322 if (access(asset->GetPath().c_str(), F_OK) != E_OK) {
323 RINGTONE_ERR_LOG("File not exist: %{public}s", asset->GetPath().c_str());
324 return E_ERR;
325 }
326 string absFilePath;
327 RingtoneXCollie ringtoneXCollie("RingtoneFile PathToRealPath time out",
328 [](void *) {
329 RINGTONE_INFO_LOG("RingtoneFile PathToRealPath time out");
330 });
331 if (!PathToRealPath(asset->GetPath(), absFilePath)) {
332 RINGTONE_ERR_LOG("Failed to get real path: %{private}s, err:%{public}d", asset->GetPath().c_str(), errno);
333 ringtoneXCollie.CancelXCollieTimer();
334 return E_ERR;
335 }
336 ringtoneXCollie.CancelXCollieTimer();
337
338 RINGTONE_DEBUG_LOG("end");
339 return RingtoneFileUtils::OpenFile(absFilePath, mode);
340 }
341
OpenVibrateFile(RingtoneDataCommand & cmd,const string & mode)342 int32_t RingtoneDataManager::OpenVibrateFile(RingtoneDataCommand &cmd, const string &mode)
343 {
344 RINGTONE_DEBUG_LOG("start");
345 RingtoneTracer tracer;
346 tracer.Start("RingtoneDataManager::OpenFile");
347 string toneId = GetIdFromUri(const_cast<Uri &>(cmd.GetUri()), VIBRATE_URI_PATH);
348 auto asset = GetVibrateAssetFromId(toneId);
349 if (asset == nullptr) {
350 RINGTONE_ERR_LOG("Failed to get VibrateAsset");
351 return E_INVALID_VALUES;
352 }
353
354 string absFilePath;
355 RingtoneXCollie ringtoneXCollie("VibrateFile PathToRealPath time out",
356 [](void *) {
357 RINGTONE_INFO_LOG("VibrateFile PathToRealPath time out");
358 });
359 if (!PathToRealPath(asset->GetPath(), absFilePath)) {
360 RINGTONE_ERR_LOG("Failed to get real path: %{private}s", asset->GetPath().c_str());
361 ringtoneXCollie.CancelXCollieTimer();
362 return E_ERR;
363 }
364 ringtoneXCollie.CancelXCollieTimer();
365 RINGTONE_DEBUG_LOG("end");
366 return RingtoneFileUtils::OpenVibrateFile(absFilePath, mode);
367 }
368
OpenFile(RingtoneDataCommand & cmd,const string & mode)369 int32_t RingtoneDataManager::OpenFile(RingtoneDataCommand &cmd, const string &mode)
370 {
371 RINGTONE_INFO_LOG("openfile uri %{public}s", cmd.GetUri().ToString().c_str());
372 RINGTONE_INFO_LOG("openfile table %{public}s", cmd.GetTableName().c_str());
373 if (cmd.GetTableName() == RINGTONE_TABLE) {
374 return OpenRingtoneFile(cmd, mode);
375 } else {
376 return OpenVibrateFile(cmd, mode);
377 }
378 }
379
SetOwner(const shared_ptr<RingtoneDataShareExtension> & datashareExternsion)380 void RingtoneDataManager::SetOwner(const shared_ptr<RingtoneDataShareExtension> &datashareExternsion)
381 {
382 extension_ = datashareExternsion;
383 }
384
GetOwner()385 shared_ptr<RingtoneDataShareExtension> RingtoneDataManager::GetOwner()
386 {
387 return extension_;
388 }
389
GetIdFromUri(Uri & uri,const std::string & uriPath)390 string RingtoneDataManager::GetIdFromUri(Uri &uri, const std::string &uriPath)
391 {
392 vector<string> segments;
393 uri.GetPathSegments(segments);
394 const int uriSegmentsCount = 3;
395 const int toneIdSegmentNumber = 2;
396 if (segments.size() != uriSegmentsCount || segments[1] != uriPath ||
397 !IsNumber(segments[toneIdSegmentNumber])) {
398 return {};
399 }
400 return segments[toneIdSegmentNumber];
401 }
402
GetRingtoneAssetFromId(const string & id)403 shared_ptr<RingtoneAsset> RingtoneDataManager::GetRingtoneAssetFromId(const string &id)
404 {
405 if ((id.empty()) || (!IsNumber(id))) {
406 RINGTONE_ERR_LOG("Id for the path is incorrect: %{private}s", id.c_str());
407 return nullptr;
408 }
409 Uri uri("");
410 RingtoneDataCommand cmd(uri, RINGTONE_TABLE, RingtoneOperationType::QUERY);
411 cmd.GetAbsRdbPredicates()->EqualTo(RINGTONE_COLUMN_TONE_ID, id);
412
413 auto resultSet = g_uniStore->Query(cmd, {RINGTONE_COLUMN_TONE_ID, RINGTONE_COLUMN_DATA});
414 if (resultSet == nullptr) {
415 RINGTONE_ERR_LOG("Failed to obtain file asset from database");
416 return nullptr;
417 }
418
419 shared_ptr<RingtoneFetchResult<RingtoneAsset>> fetchResult = make_shared<RingtoneFetchResult<RingtoneAsset>>();
420 if (fetchResult == nullptr) {
421 RINGTONE_ERR_LOG("Failed to obtain fetch file result");
422 return nullptr;
423 }
424 return fetchResult->GetObjectFromRdb(resultSet, 0);
425 }
426
GetVibrateAssetFromId(const std::string & id)427 std::shared_ptr<VibrateAsset> RingtoneDataManager::GetVibrateAssetFromId(const std::string &id)
428 {
429 if ((id.empty()) || (!IsNumber(id))) {
430 RINGTONE_ERR_LOG("Id for the path is incorrect: %{private}s", id.c_str());
431 return nullptr;
432 }
433 Uri uri("");
434 RingtoneDataCommand cmd(uri, VIBRATE_TABLE, RingtoneOperationType::QUERY);
435 cmd.GetAbsRdbPredicates()->EqualTo(VIBRATE_COLUMN_VIBRATE_ID, id);
436
437 auto resultSet = g_uniStore->Query(cmd, {VIBRATE_COLUMN_VIBRATE_ID, VIBRATE_COLUMN_DATA});
438 if (resultSet == nullptr) {
439 RINGTONE_ERR_LOG("Failed to obtain file asset from database");
440 return nullptr;
441 }
442
443 shared_ptr<RingtoneFetchResult<VibrateAsset>> fetchResult = make_shared<RingtoneFetchResult<VibrateAsset>>();
444 if (fetchResult == nullptr) {
445 RINGTONE_ERR_LOG("Failed to obtain fetch file result");
446 return nullptr;
447 }
448 return fetchResult->GetObjectFromRdb(resultSet, 0);
449 }
450
ClearRingtoneDataMgr()451 void RingtoneDataManager::ClearRingtoneDataMgr()
452 {
453 lock_guard<shared_mutex> lock(mgrSharedMutex_);
454
455 refCnt_--;
456 if (refCnt_.load() > 0) {
457 RINGTONE_DEBUG_LOG("still other extension exist");
458 return;
459 }
460
461 extension_ = nullptr;
462 }
463 } // namespace Media
464 } // namespace OHOS
465