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 "RingtoneRestoreBase"
17
18 #include "ringtone_restore_base.h"
19
20 #include "datashare_ext_ability.h"
21 #include "datashare_ext_ability_context.h"
22 #include "rdb_helper.h"
23 #include "rdb_sql_utils.h"
24 #include "result_set.h"
25 #include "result_set_utils.h"
26 #include "ringtone_restore_type.h"
27 #include "ringtone_restore_db_utils.h"
28 #include "ringtone_db_const.h"
29 #include "ringtone_errno.h"
30 #include "ringtone_file_utils.h"
31 #include "ringtone_utils.h"
32 #include "ringtone_log.h"
33 #include "ringtone_mimetype_utils.h"
34 #include "ringtone_rdb_transaction.h"
35 #include "ringtone_rdbstore.h"
36 #include "ringtone_scanner_manager.h"
37 #include "preferences_helper.h"
38 #include "dfx_const.h"
39
40 namespace OHOS {
41 namespace Media {
42 using namespace std;
43
44 static const char RINGTONE_PARAMETER_SCANNER_COMPLETED_KEY[] = "ringtone.scanner.completed";
45 static const int RINGTONE_PARAMETER_SCANNER_COMPLETED_TRUE = 1;
46 static const int RINGTONE_PARAMETER_SCANNER_COMPLETED_FALSE = 0;
47
Init(const string & backupPath)48 int32_t RingtoneRestoreBase::Init(const string &backupPath)
49 {
50 if (localRdb_ != nullptr) {
51 return E_OK;
52 }
53 auto context = AbilityRuntime::Context::GetApplicationContext();
54 if (context == nullptr) {
55 RINGTONE_ERR_LOG("Failed to get context");
56 return E_FAIL;
57 }
58
59 auto rdbStore = RingtoneRdbStore::GetInstance(context);
60 if (rdbStore == nullptr) {
61 RINGTONE_ERR_LOG("rdbStore initialization failed");
62 return E_RDB;
63 }
64
65 int32_t errCode = 0;
66 string realPath = NativeRdb::RdbSqlUtils::GetDefaultDatabasePath(RINGTONE_LIBRARY_DB_PATH_EL1,
67 RINGTONE_LIBRARY_DB_NAME, errCode);
68 int32_t err = RingtoneRestoreDbUtils::InitDb(localRdb_, RINGTONE_LIBRARY_DB_PATH_EL1, realPath,
69 RINGTONE_BUNDLE_NAME, true);
70 if (err != E_OK) {
71 RINGTONE_ERR_LOG("medialibrary rdb fail, err = %{public}d", err);
72 return E_FAIL;
73 }
74 settingMgr_ = make_unique<RingtoneSettingManager>(localRdb_);
75 if (settingMgr_ == nullptr) {
76 RINGTONE_ERR_LOG("create ringtone setting manager failed");
77 return E_FAIL;
78 }
79
80 return E_OK;
81 }
82
StartRestore()83 int32_t RingtoneRestoreBase::StartRestore()
84 {
85 RingtoneFileUtils::AccessRingtoneDir();
86 int32_t errCode = RingtoneMimeTypeUtils::InitMimeTypeMap();
87 if (errCode != E_OK) {
88 RINGTONE_ERR_LOG("get mine type map error: %{public}d", errCode);
89 return errCode;
90 }
91 shared_ptr<NativePreferences::Preferences> prefs =
92 NativePreferences::PreferencesHelper::GetPreferences(COMMON_XML_EL1, errCode);
93 if (!prefs) {
94 RINGTONE_ERR_LOG("get preferences error: %{public}d", errCode);
95 return E_FAIL;
96 }
97 int isCompleted = prefs->GetInt(RINGTONE_PARAMETER_SCANNER_COMPLETED_KEY,
98 RINGTONE_PARAMETER_SCANNER_COMPLETED_FALSE);
99 if (!isCompleted) {
100 RingtoneScannerManager::GetInstance()->Start(true);
101 prefs->PutInt(RINGTONE_PARAMETER_SCANNER_COMPLETED_KEY, RINGTONE_PARAMETER_SCANNER_COMPLETED_TRUE);
102 prefs->FlushSync();
103 }
104 return E_OK;
105 }
106
MoveFile(const std::string & src,const std::string & dst)107 bool RingtoneRestoreBase::MoveFile(const std::string &src, const std::string &dst)
108 {
109 if (RingtoneFileUtils::MoveFile(src, dst)) {
110 return true;
111 }
112
113 if (!RingtoneFileUtils::CopyFileUtil(src, dst)) {
114 RINGTONE_ERR_LOG("copy-file failed, src: %{public}s, err: %{public}s", src.c_str(), strerror(errno));
115 return false;
116 }
117
118 if (!RingtoneFileUtils::DeleteFile(src)) {
119 RINGTONE_ERR_LOG("remove-file failed, filePath: %{public}s, err: %{public}s", src.c_str(), strerror(errno));
120 }
121
122 return true;
123 }
124
NeedCommitSetting(const std::string & typeColumn,const std::string & sourceColumn,int type,int allSetType)125 bool RingtoneRestoreBase::NeedCommitSetting(const std::string &typeColumn, const std::string &sourceColumn,
126 int type, int allSetType)
127 {
128 auto type2Str = std::to_string(type);
129 auto allSetTypeStr = std::to_string(allSetType);
130 // allSetType is for those settings with both sim cards
131 string queryCountSql = "SELECT count(1) as count FROM " + RINGTONE_TABLE + " WHERE " + sourceColumn +
132 " = 2 AND (" + typeColumn + " = " + type2Str + " OR " + typeColumn + " = " + allSetTypeStr + " );";
133 RINGTONE_INFO_LOG("queryCountSql: %{public}s", queryCountSql.c_str());
134
135 int32_t count = RingtoneRestoreDbUtils::QueryInt(localRdb_, queryCountSql, "count");
136 RINGTONE_INFO_LOG("got count = %{public}d", count);
137
138 return !(count>0);
139 }
140
CheckSetting(FileInfo & info)141 void RingtoneRestoreBase::CheckSetting(FileInfo &info)
142 {
143 RINGTONE_INFO_LOG("checking setting: %{public}s", info.toString().c_str());
144 if ((info.shotToneType > SHOT_TONE_TYPE_NOT) && (info.shotToneType < SHOT_TONE_TYPE_MAX) &&
145 (info.shotToneSourceType == SOURCE_TYPE_CUSTOMISED) && NeedCommitSetting(RINGTONE_COLUMN_SHOT_TONE_TYPE,
146 RINGTONE_COLUMN_SHOT_TONE_SOURCE_TYPE, info.shotToneType, SHOT_TONE_TYPE_SIM_CARD_BOTH)) {
147 settingMgr_->CommitSetting(info.toneId, info.restorePath, TONE_SETTING_TYPE_SHOT, info.shotToneType,
148 info.shotToneSourceType);
149 RINGTONE_INFO_LOG("commit as shottone");
150 }
151 if (info.ringToneType > RING_TONE_TYPE_NOT && info.ringToneType < RING_TONE_TYPE_MAX &&
152 info.ringToneSourceType == SOURCE_TYPE_CUSTOMISED && NeedCommitSetting(RINGTONE_COLUMN_RING_TONE_TYPE,
153 RINGTONE_COLUMN_RING_TONE_SOURCE_TYPE, info.ringToneType, RING_TONE_TYPE_SIM_CARD_BOTH)) {
154 settingMgr_->CommitSetting(info.toneId, info.restorePath, TONE_SETTING_TYPE_RINGTONE, info.ringToneType,
155 info.ringToneSourceType);
156 RINGTONE_INFO_LOG("commit as ringtone");
157 }
158 if (info.notificationToneType == NOTIFICATION_TONE_TYPE &&
159 info.notificationToneSourceType == SOURCE_TYPE_CUSTOMISED &&
160 NeedCommitSetting(RINGTONE_COLUMN_NOTIFICATION_TONE_TYPE,
161 RINGTONE_COLUMN_NOTIFICATION_TONE_SOURCE_TYPE, info.notificationToneType, NOTIFICATION_TONE_TYPE)) {
162 settingMgr_->CommitSetting(info.toneId, info.restorePath, TONE_SETTING_TYPE_NOTIFICATION,
163 info.notificationToneType, info.notificationToneSourceType);
164 RINGTONE_INFO_LOG("commit as notificationTone");
165 }
166 if (info.alarmToneType == ALARM_TONE_TYPE && info.alarmToneSourceType == SOURCE_TYPE_CUSTOMISED &&
167 NeedCommitSetting(RINGTONE_COLUMN_ALARM_TONE_TYPE, RINGTONE_COLUMN_ALARM_TONE_SOURCE_TYPE,
168 info.alarmToneType, ALARM_TONE_TYPE)) {
169 settingMgr_->CommitSetting(info.toneId, info.restorePath, TONE_SETTING_TYPE_ALARM, info.alarmToneType,
170 info.alarmToneSourceType);
171 RINGTONE_INFO_LOG("commit as alarmTone");
172 }
173 }
174
InsertTones(std::vector<FileInfo> & fileInfos)175 int32_t RingtoneRestoreBase::InsertTones(std::vector<FileInfo> &fileInfos)
176 {
177 if (localRdb_ == nullptr) {
178 RINGTONE_ERR_LOG("localRdb_ is null");
179 return E_FAIL;
180 }
181 if (fileInfos.empty()) {
182 RINGTONE_ERR_LOG("fileInfos are empty, not need restore");
183 return E_OK;
184 }
185 vector<NativeRdb::ValuesBucket> values = MakeInsertValues(fileInfos);
186 int64_t rowNum = 0;
187 int32_t errCode = BatchInsert(RINGTONE_TABLE, values, rowNum);
188 if (errCode != E_OK) {
189 RINGTONE_ERR_LOG("fail to batch insert");
190 return errCode;
191 }
192
193 OnFinished(fileInfos);
194 return E_OK;
195 }
196
FlushSettings()197 void RingtoneRestoreBase::FlushSettings()
198 {
199 if (settingMgr_ != nullptr) {
200 settingMgr_->FlushSettings();
201 } else {
202 RINGTONE_ERR_LOG("ringtone setting mgr is nullptr");
203 }
204 }
205
BatchInsert(const std::string & tableName,std::vector<NativeRdb::ValuesBucket> & values,int64_t & rowNum)206 int32_t RingtoneRestoreBase::BatchInsert(const std::string &tableName, std::vector<NativeRdb::ValuesBucket> &values,
207 int64_t &rowNum)
208 {
209 int32_t errCode = E_ERR;
210 RingtoneRdbTransaction transactionOprn(localRdb_);
211 errCode = transactionOprn.Start();
212 if (errCode != E_OK) {
213 RINGTONE_ERR_LOG("can not get rdb before batch insert");
214 return errCode;
215 }
216 errCode = localRdb_->BatchInsert(rowNum, tableName, values);
217 if (errCode != E_OK) {
218 RINGTONE_ERR_LOG("InsertSql failed, errCode: %{public}d, rowNum: %{public}ld.", errCode, (long)rowNum);
219 return errCode;
220 }
221 transactionOprn.Finish();
222 return errCode;
223 }
224
GetRestoreDir(const int32_t toneType)225 string RingtoneRestoreBase::GetRestoreDir(const int32_t toneType)
226 {
227 string path = {};
228 if (toneType == ToneType::TONE_TYPE_ALARM) {
229 path = RINGTONE_RESTORE_DIR + "/" + "alarms";
230 } else if (toneType == TONE_TYPE_RINGTONE) {
231 path = RINGTONE_RESTORE_DIR + "/" + "ringtones";
232 } else if (toneType == TONE_TYPE_NOTIFICATION) {
233 path = RINGTONE_RESTORE_DIR + "/" + "notifications";
234 } else {
235 path = {};
236 }
237 return path;
238 }
239
MakeInsertValues(std::vector<FileInfo> & fileInfos)240 vector<NativeRdb::ValuesBucket> RingtoneRestoreBase::MakeInsertValues(std::vector<FileInfo> &fileInfos)
241 {
242 vector<NativeRdb::ValuesBucket> values;
243 for (auto it = fileInfos.begin(); it != fileInfos.end(); it++) {
244 auto destDir = GetRestoreDir(it->toneType);
245 if (destDir.empty() || !OnPrepare(*it, destDir)) {
246 continue;
247 }
248
249 NativeRdb::ValuesBucket value = SetInsertValue(*it);
250 if (value.IsEmpty()) {
251 continue;
252 }
253 if (it->doInsert) { // only when this value needs to be inserted
254 values.emplace_back(value);
255 }
256 CheckSetting(*it);
257 }
258 return values;
259 }
260
SetInsertValue(const FileInfo & fileInfo)261 NativeRdb::ValuesBucket RingtoneRestoreBase::SetInsertValue(const FileInfo &fileInfo)
262 {
263 if (fileInfo.restorePath.empty() || fileInfo.data.empty()) {
264 return {};
265 }
266 NativeRdb::ValuesBucket values;
267 values.PutString(RINGTONE_COLUMN_DATA, fileInfo.restorePath);
268 values.PutInt(RINGTONE_COLUMN_SIZE, fileInfo.size);
269 values.PutString(RINGTONE_COLUMN_DISPLAY_NAME, fileInfo.displayName);
270 values.PutString(RINGTONE_COLUMN_TITLE, fileInfo.title);
271 values.PutInt(RINGTONE_COLUMN_MEDIA_TYPE, fileInfo.mediaType);
272 values.PutInt(RINGTONE_COLUMN_TONE_TYPE, fileInfo.toneType);
273 values.PutString(RINGTONE_COLUMN_MIME_TYPE, fileInfo.mimeType);
274 values.PutInt(RINGTONE_COLUMN_SOURCE_TYPE, fileInfo.sourceType);
275 values.PutLong(RINGTONE_COLUMN_DATE_ADDED, fileInfo.dateAdded);
276 values.PutLong(RINGTONE_COLUMN_DATE_MODIFIED, fileInfo.dateModified);
277 values.PutLong(RINGTONE_COLUMN_DATE_TAKEN, fileInfo.dateTaken);
278 values.PutInt(RINGTONE_COLUMN_DURATION, fileInfo.duration);
279 values.PutInt(RINGTONE_COLUMN_SCANNER_FLAG, fileInfo.scannerFlag);
280 // ringtone setting infos
281 values.PutInt(RINGTONE_COLUMN_SHOT_TONE_TYPE, SHOT_TONE_TYPE_DEFAULT);
282 values.PutInt(RINGTONE_COLUMN_SHOT_TONE_SOURCE_TYPE, SHOT_TONE_SOURCE_TYPE_DEFAULT);
283 values.PutInt(RINGTONE_COLUMN_NOTIFICATION_TONE_TYPE, NOTIFICATION_TONE_TYPE_DEFAULT);
284 values.PutInt(RINGTONE_COLUMN_NOTIFICATION_TONE_SOURCE_TYPE, NOTIFICATION_TONE_SOURCE_TYPE_DEFAULT);
285 values.PutInt(RINGTONE_COLUMN_RING_TONE_TYPE, RING_TONE_TYPE_DEFAULT);
286 values.PutInt(RINGTONE_COLUMN_RING_TONE_SOURCE_TYPE, RING_TONE_SOURCE_TYPE_DEFAULT);
287 values.PutInt(RINGTONE_COLUMN_ALARM_TONE_TYPE, ALARM_TONE_TYPE_DEFAULT);
288 values.PutInt(RINGTONE_COLUMN_ALARM_TONE_SOURCE_TYPE, ALARM_TONE_SOURCE_TYPE_DEFAULT);
289
290 return values;
291 }
292
MoveDirectory(const std::string & srcDir,const std::string & dstDir)293 int32_t RingtoneRestoreBase::MoveDirectory(const std::string &srcDir, const std::string &dstDir)
294 {
295 if (!RingtoneFileUtils::CreateDirectory(dstDir)) {
296 RINGTONE_ERR_LOG("Create dstDir %{private}s failed", dstDir.c_str());
297 return E_FAIL;
298 }
299 for (const auto &dirEntry : std::filesystem::directory_iterator{ srcDir }) {
300 std::string srcFilePath = dirEntry.path();
301 std::string tmpFilePath = srcFilePath;
302 std::string dstFilePath = tmpFilePath.replace(0, srcDir.length(), dstDir);
303 if (!MoveFile(srcFilePath, dstFilePath)) {
304 RINGTONE_ERR_LOG("Move file from %{private}s to %{private}s failed", srcFilePath.c_str(),
305 dstFilePath.c_str());
306 return E_FAIL;
307 }
308 }
309 return E_OK;
310 }
311
ExtractMetaFromColumn(const shared_ptr<NativeRdb::ResultSet> & resultSet,unique_ptr<RingtoneMetadata> & metadata,const std::string & col)312 void RingtoneRestoreBase::ExtractMetaFromColumn(const shared_ptr<NativeRdb::ResultSet> &resultSet,
313 unique_ptr<RingtoneMetadata> &metadata, const std::string &col)
314 {
315 RingtoneResultSetDataType dataType = RingtoneResultSetDataType::DATA_TYPE_NULL;
316 RingtoneMetadata::RingtoneMetadataFnPtr requestFunc = nullptr;
317 auto itr = metadata->memberFuncMap_.find(col);
318 if (itr != metadata->memberFuncMap_.end()) {
319 dataType = itr->second.first;
320 requestFunc = itr->second.second;
321 } else {
322 RINGTONE_ERR_LOG("column name invalid %{private}s", col.c_str());
323 return;
324 }
325
326 std::variant<int32_t, std::string, int64_t, double> data =
327 ResultSetUtils::GetValFromColumn<const shared_ptr<NativeRdb::ResultSet>>(col, resultSet, dataType);
328
329 if (requestFunc != nullptr) {
330 (metadata.get()->*requestFunc)(data);
331 }
332 }
333
PopulateMetadata(const shared_ptr<NativeRdb::ResultSet> & resultSet,unique_ptr<RingtoneMetadata> & metaData)334 int32_t RingtoneRestoreBase::PopulateMetadata(const shared_ptr<NativeRdb::ResultSet> &resultSet,
335 unique_ptr<RingtoneMetadata> &metaData)
336 {
337 std::vector<std::string> columnNames;
338 int32_t err = resultSet->GetAllColumnNames(columnNames);
339 if (err != NativeRdb::E_OK) {
340 RINGTONE_ERR_LOG("failed to get all column names");
341 return E_RDB;
342 }
343
344 for (const auto &col : columnNames) {
345 ExtractMetaFromColumn(resultSet, metaData, col);
346 }
347
348 return E_OK;
349 }
350 } // namespace Media
351 } // namespace OHOS
352