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