• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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