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