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