• 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 
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