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
127 auto asset = GetRingtoneAssetFromId(to_string(outRowId));
128 if (asset == nullptr) {
129 int32_t deleteRet = DeleteRingtoneRowById(outRowId);
130 RINGTONE_ERR_LOG("Failed to get RingtoneAsset, delete row %{public}d from db, return %{public}d",
131 static_cast<int32_t>(outRowId), deleteRet);
132 return E_INVALID_VALUES;
133 }
134
135 auto ret = RingtoneFileUtils::CreateFile(asset->GetPath());
136 if (ret != E_SUCCESS) {
137 int32_t deleteRet = DeleteRingtoneRowById(outRowId);
138 RINGTONE_ERR_LOG("Failed to create file, delete row %{public}d from db, return %{public}d",
139 static_cast<int32_t>(outRowId), deleteRet);
140 return ret;
141 }
142
143 RINGTONE_DEBUG_LOG("end");
144 return static_cast<int32_t>(outRowId);
145 }
146
DeleteFileFromResultSet(std::shared_ptr<NativeRdb::ResultSet> & resultSet)147 int32_t RingtoneDataManager::DeleteFileFromResultSet(std::shared_ptr<NativeRdb::ResultSet> &resultSet)
148 {
149 auto count = 0;
150 if (resultSet == nullptr) {
151 RINGTONE_ERR_LOG("resultSet is nullptr");
152 return E_ERR;
153 }
154 auto ret = resultSet->GetRowCount(count);
155 if (ret != NativeRdb::E_OK) {
156 RINGTONE_ERR_LOG("get rdbstore failed");
157 return E_HAS_DB_ERROR;
158 }
159 if (count == 0) {
160 RINGTONE_ERR_LOG("have no files to delete");
161 return E_SUCCESS;
162 }
163
164 shared_ptr<RingtoneFetchResult<RingtoneAsset>> fetchResult = make_shared<RingtoneFetchResult<RingtoneAsset>>();
165 if (fetchResult == nullptr) {
166 RINGTONE_ERR_LOG("Failed to obtain fetch file result");
167 return E_ERR;
168 }
169
170 for (auto i = 0; i < count; i++) {
171 auto asset = fetchResult->GetObjectFromRdb(resultSet, i);
172 if (asset == nullptr) {
173 RINGTONE_ERR_LOG("asset is nullptr");
174 continue;
175 }
176 RingtoneFileUtils::DeleteFile(asset->GetPath());
177 }
178
179 return E_SUCCESS;
180 }
181
Delete(RingtoneDataCommand & cmd,const DataSharePredicates & predicates,bool onlyDb)182 int32_t RingtoneDataManager::Delete(RingtoneDataCommand &cmd, const DataSharePredicates &predicates, bool onlyDb)
183 {
184 RINGTONE_DEBUG_LOG("start");
185 shared_lock<shared_mutex> sharedLock(mgrSharedMutex_);
186 if (refCnt_.load() <= 0) {
187 RINGTONE_DEBUG_LOG("RingtoneDataManager is not initialized");
188 return E_FAIL;
189 }
190 if (g_uniStore == nullptr) {
191 RINGTONE_ERR_LOG("rdb store is not initialized");
192 return E_DB_FAIL;
193 }
194
195 string uriString = cmd.GetUri().ToString();
196 if (uriString.find(RINGTONE_URI) == string::npos) {
197 RINGTONE_ERR_LOG("Not Data ability Uri");
198 return E_INVALID_URI;
199 }
200
201 NativeRdb::RdbPredicates rdbPredicate = RdbUtils::ToPredicates(predicates, cmd.GetTableName());
202 cmd.GetAbsRdbPredicates()->SetWhereClause(rdbPredicate.GetWhereClause());
203 cmd.GetAbsRdbPredicates()->SetWhereArgs(rdbPredicate.GetWhereArgs());
204
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 int32_t deletedRows = E_HAS_DB_ERROR;
212 int32_t ret = g_uniStore->Delete(cmd, deletedRows);
213 if (ret != NativeRdb::E_OK || deletedRows <= 0) {
214 RINGTONE_ERR_LOG("Delete operation failed. Result %{public}d.", ret);
215 deletedRows = E_HAS_DB_ERROR;
216 }
217
218 RINGTONE_DEBUG_LOG("end");
219 return deletedRows;
220 }
221
Update(RingtoneDataCommand & cmd,const DataShareValuesBucket & dataShareValue,const DataSharePredicates & predicates)222 int32_t RingtoneDataManager::Update(RingtoneDataCommand &cmd, const DataShareValuesBucket &dataShareValue,
223 const DataSharePredicates &predicates)
224 {
225 RINGTONE_DEBUG_LOG("start");
226 shared_lock<shared_mutex> sharedLock(mgrSharedMutex_);
227 if (refCnt_.load() <= 0) {
228 RINGTONE_DEBUG_LOG("RingtoneDataManager is not initialized");
229 return E_FAIL;
230 }
231 if (g_uniStore == nullptr) {
232 RINGTONE_ERR_LOG("rdb store is not initialized");
233 return E_DB_FAIL;
234 }
235
236 ValuesBucket value = RdbUtils::ToValuesBucket(dataShareValue);
237 if (value.IsEmpty()) {
238 RINGTONE_ERR_LOG("RingtoneDataManager Update:Input parameter is invalid");
239 return E_INVALID_VALUES;
240 }
241
242 cmd.SetValueBucket(value);
243 cmd.SetDataSharePred(predicates);
244 NativeRdb::RdbPredicates rdbPredicate = RdbUtils::ToPredicates(predicates, cmd.GetTableName());
245 cmd.GetAbsRdbPredicates()->SetWhereClause(rdbPredicate.GetWhereClause());
246 cmd.GetAbsRdbPredicates()->SetWhereArgs(rdbPredicate.GetWhereArgs());
247
248 int32_t updatedRows = E_HAS_DB_ERROR;
249 int32_t result = g_uniStore->Update(cmd, updatedRows);
250 if (result != NativeRdb::E_OK || updatedRows <= 0) {
251 RINGTONE_ERR_LOG("Update operation failed. Result %{public}d. Updated %{public}d", result, updatedRows);
252 updatedRows = E_HAS_DB_ERROR;
253 }
254
255 RINGTONE_DEBUG_LOG("end");
256 return updatedRows;
257 }
258
Query(RingtoneDataCommand & cmd,const vector<string> & columns,const DataSharePredicates & predicates,int & errCode)259 shared_ptr<ResultSetBridge> RingtoneDataManager::Query(RingtoneDataCommand &cmd,
260 const vector<string> &columns, const DataSharePredicates &predicates, int &errCode)
261 {
262 RINGTONE_DEBUG_LOG("start");
263 shared_lock<shared_mutex> sharedLock(mgrSharedMutex_);
264 if (refCnt_.load() <= 0) {
265 RINGTONE_DEBUG_LOG("RingtoneDataManager is not initialized");
266 return nullptr;
267 }
268 if (g_uniStore == nullptr) {
269 RINGTONE_ERR_LOG("rdb store is not initialized");
270 return nullptr;
271 }
272
273 RingtoneTracer tracer;
274 tracer.Start("RingtoneDataManager::Query");
275 cmd.SetDataSharePred(predicates);
276 NativeRdb::RdbPredicates rdbPredicate = RdbUtils::ToPredicates(predicates, cmd.GetTableName());
277 cmd.GetAbsRdbPredicates()->SetWhereClause(rdbPredicate.GetWhereClause());
278 cmd.GetAbsRdbPredicates()->SetWhereArgs(rdbPredicate.GetWhereArgs());
279 cmd.GetAbsRdbPredicates()->SetOrder(rdbPredicate.GetOrder());
280
281 auto absResultSet = g_uniStore->Query(cmd, columns);
282
283 RINGTONE_DEBUG_LOG("end");
284 return RdbUtils::ToResultSetBridge(absResultSet);
285 }
286
IsNumber(const string & str)287 static bool IsNumber(const string &str)
288 {
289 if (str.empty()) {
290 RINGTONE_DEBUG_LOG("IsNumber input is empty ");
291 return false;
292 }
293
294 for (char const &c : str) {
295 if (isdigit(c) == 0) {
296 return false;
297 }
298 }
299 return true;
300 }
301
OpenFile(RingtoneDataCommand & cmd,const string & mode)302 int32_t RingtoneDataManager::OpenFile(RingtoneDataCommand &cmd, const string &mode)
303 {
304 RINGTONE_DEBUG_LOG("start");
305 RingtoneTracer tracer;
306 tracer.Start("RingtoneDataManager::OpenFile");
307 string toneId = GetIdFromUri(const_cast<Uri &>(cmd.GetUri()));
308 auto asset = GetRingtoneAssetFromId(toneId);
309 if (asset == nullptr) {
310 RINGTONE_ERR_LOG("Failed to get RingtoneAsset");
311 return E_INVALID_VALUES;
312 }
313
314 string absFilePath;
315 if (!PathToRealPath(asset->GetPath(), absFilePath)) {
316 RINGTONE_ERR_LOG("Failed to get real path: %{private}s", asset->GetPath().c_str());
317 return E_ERR;
318 }
319
320 RINGTONE_DEBUG_LOG("end");
321 return RingtoneFileUtils::OpenFile(absFilePath, mode);
322 }
323
SetOwner(const shared_ptr<RingtoneDataShareExtension> & datashareExternsion)324 void RingtoneDataManager::SetOwner(const shared_ptr<RingtoneDataShareExtension> &datashareExternsion)
325 {
326 extension_ = datashareExternsion;
327 }
328
GetOwner()329 shared_ptr<RingtoneDataShareExtension> RingtoneDataManager::GetOwner()
330 {
331 return extension_;
332 }
333
GetIdFromUri(Uri & uri)334 string RingtoneDataManager::GetIdFromUri(Uri &uri)
335 {
336 vector<string> segments;
337 uri.GetPathSegments(segments);
338 const int uriSegmentsCount = 3;
339 const int toneIdSegmentNumber = 2;
340 if (segments.size() != uriSegmentsCount || segments[1] != RINGTONE_URI_PATH ||
341 !IsNumber(segments[toneIdSegmentNumber])) {
342 return {};
343 }
344 return segments[toneIdSegmentNumber];
345 }
346
GetRingtoneAssetFromId(const string & id)347 shared_ptr<RingtoneAsset> RingtoneDataManager::GetRingtoneAssetFromId(const string &id)
348 {
349 if ((id.empty()) || (!IsNumber(id)) || (stoi(id) == -1)) {
350 RINGTONE_ERR_LOG("Id for the path is incorrect: %{private}s", id.c_str());
351 return nullptr;
352 }
353 Uri uri("");
354 RingtoneDataCommand cmd(uri, RINGTONE_TABLE, RingtoneOperationType::QUERY);
355 cmd.GetAbsRdbPredicates()->EqualTo(RINGTONE_COLUMN_TONE_ID, id);
356
357 auto resultSet = g_uniStore->Query(cmd, {RINGTONE_COLUMN_TONE_ID, RINGTONE_COLUMN_DATA});
358 if (resultSet == nullptr) {
359 RINGTONE_ERR_LOG("Failed to obtain file asset from database");
360 return nullptr;
361 }
362
363 shared_ptr<RingtoneFetchResult<RingtoneAsset>> fetchResult = make_shared<RingtoneFetchResult<RingtoneAsset>>();
364 if (fetchResult == nullptr) {
365 RINGTONE_ERR_LOG("Failed to obtain fetch file result");
366 return nullptr;
367 }
368 return fetchResult->GetObjectFromRdb(resultSet, 0);
369 }
370
ClearRingtoneDataMgr()371 void RingtoneDataManager::ClearRingtoneDataMgr()
372 {
373 lock_guard<shared_mutex> lock(mgrSharedMutex_);
374
375 refCnt_--;
376 if (refCnt_.load() > 0) {
377 RINGTONE_DEBUG_LOG("still other extension exist");
378 return;
379 }
380
381 extension_ = nullptr;
382 }
383 } // namespace Media
384 } // namespace OHOS
385