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