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 "RingtoneDualFwkRestore"
17
18 #include "ringtone_dualfwk_restore.h"
19
20 #include <fcntl.h>
21 #include <sys/sendfile.h>
22 #include <sys/stat.h>
23 #include <sstream>
24
25 #include "datashare_helper.h"
26 #include "datashare_predicates.h"
27 #include "directory_ex.h"
28 #include "dualfwk_conf_parser.h"
29 #include "dualfwk_conf_loader.h"
30 #include "dualfwk_sound_setting.h"
31 #include "iservice_registry.h"
32 #include "result_set_utils.h"
33 #include "ringtone_errno.h"
34 #include "ringtone_file_utils.h"
35 #include "ringtone_log.h"
36 #include "ringtone_restore_db_utils.h"
37 #include "ringtone_restore_base.h"
38 #include "ringtone_restore_type.h"
39 #include "ringtone_type.h"
40 #include "ringtone_utils.h"
41 #include "customised_tone_processor.h"
42
43 namespace OHOS {
44 namespace Media {
45 using namespace std;
46
47 static const string DUALFWK_SOUND_CONF_XML = "backup";
48
LoadDualFwkConf(const std::string & backupPath)49 int32_t RingtoneDualFwkRestore::LoadDualFwkConf(const std::string &backupPath)
50 {
51 DualFwkConfLoader confLoader;
52 if (confLoader.Init() != E_OK) {
53 RINGTONE_ERR_LOG("Failed to initialize DualFwkConfLoader.");
54 return E_FAIL;
55 }
56 DualFwkConf conf;
57 confLoader.Load(conf, RESTORE_SCENE_TYPE_DUAL_UPGRADE, backupPath);
58 confLoader.ShowConf(conf);
59
60 dualFwkSetting_ = std::make_unique<DualFwkSoundSetting>();
61 if (dualFwkSetting_ == nullptr) {
62 RINGTONE_ERR_LOG("Create DualFwkSoundSetting Failed.");
63 return E_FAIL;
64 }
65
66 dualFwkSetting_->ProcessConf(conf);
67 return E_SUCCESS;
68 }
69
ParseDualFwkConf(const string & xml)70 int32_t RingtoneDualFwkRestore::ParseDualFwkConf(const string &xml)
71 {
72 auto parser = std::make_unique<DualFwkConfParser>(xml);
73 if (parser == nullptr) {
74 RINGTONE_ERR_LOG("Create DualFwkConfParser Failed.");
75 return E_FAIL;
76 }
77
78 dualFwkSetting_ = std::make_unique<DualFwkSoundSetting>();
79 if (dualFwkSetting_ == nullptr) {
80 RINGTONE_ERR_LOG("Create DualFwkSoundSetting Failed.");
81 return E_FAIL;
82 }
83
84 if (parser->Parse() != E_SUCCESS) {
85 RINGTONE_ERR_LOG("parse dualfwk-sound-setting-xml Failed.");
86 return E_FAIL;
87 }
88
89 parser->ConfTraval([this](std::unique_ptr<DualFwkConfRow> &conf) -> void {
90 dualFwkSetting_->ProcessConfRow(conf);
91 });
92
93 return E_SUCCESS;
94 }
95
Init(const std::string & backupPath)96 int32_t RingtoneDualFwkRestore::Init(const std::string &backupPath)
97 {
98 RINGTONE_INFO_LOG("Init db start");
99 if (backupPath.empty()) {
100 RINGTONE_ERR_LOG("error: backup path is null");
101 return E_INVALID_ARGUMENTS;
102 }
103
104 if (LoadDualFwkConf(backupPath + "/" + DUALFWK_SOUND_CONF_XML) != E_SUCCESS) {
105 return E_FAIL;
106 }
107
108 if (RingtoneRestoreBase::Init(backupPath) != E_OK) {
109 return E_FAIL;
110 }
111
112 RINGTONE_INFO_LOG("Init db successfully");
113 return E_OK;
114 }
115
116 static const string KEY_API_VERSION = "API_VERSION";
MakeBatchQueryWhereClause(const std::vector<std::string> & names,const std::string & predicateColumn)117 static std::string MakeBatchQueryWhereClause(const std::vector<std::string> &names,
118 const std::string &predicateColumn)
119 {
120 std::stringstream prefixSs;
121 prefixSs << predicateColumn << " in (";
122 bool start = true;
123 for (const auto& name: names) {
124 if (start) {
125 start = false;
126 } else {
127 prefixSs << ",";
128 }
129 prefixSs << "\"" << name << "\"";
130 }
131 prefixSs << ")";
132 return prefixSs.str();
133 }
134
QueryRingToneDbForFileInfo(std::shared_ptr<NativeRdb::RdbStore> rdbStore,const std::vector<std::string> & names,std::map<std::string,std::vector<std::shared_ptr<FileInfo>>> & infoMap,const std::string & predicateColumn)135 int32_t RingtoneDualFwkRestore::QueryRingToneDbForFileInfo(std::shared_ptr<NativeRdb::RdbStore> rdbStore,
136 const std::vector<std::string> &names, std::map<std::string, std::vector<std::shared_ptr<FileInfo>>> &infoMap,
137 const std::string &predicateColumn)
138 {
139 if (rdbStore == nullptr) {
140 RINGTONE_ERR_LOG("rdb_ is nullptr, Maybe init failed.");
141 return E_FAIL;
142 }
143 string whereClause = MakeBatchQueryWhereClause(names, predicateColumn);
144 std::string queryCountSql = "SELECT * FROM " + RINGTONE_TABLE +
145 " WHERE " + whereClause + " AND " +
146 RINGTONE_COLUMN_MEDIA_TYPE + "=" + std::to_string(RINGTONE_MEDIA_TYPE_AUDIO) + ";";
147 RINGTONE_INFO_LOG("Querying ringtonedb where %{public}s", whereClause.c_str());
148
149 auto resultSet = rdbStore->QuerySql(queryCountSql);
150 if (resultSet == nullptr) {
151 RINGTONE_WARN_LOG("resultset for %{public}s is null", whereClause.c_str());
152 return E_FAIL;
153 }
154 int count = 0;
155 resultSet->GetRowCount(count);
156 RINGTONE_INFO_LOG("Querying ringtonedb where %{public}s, got %{public}d records",
157 whereClause.c_str(), count);
158
159 if (count <= 0) {
160 RINGTONE_WARN_LOG("resultset for %{public}s is empty", whereClause.c_str());
161 return E_SUCCESS;
162 }
163
164 for (int i = 0; i < count; i++) {
165 resultSet->GoToNextRow();
166 auto metaData = std::make_unique<RingtoneMetadata>();
167 if (PopulateMetadata(resultSet, metaData) != E_OK) {
168 return E_FAIL;
169 }
170 auto infoPtr = std::make_shared<FileInfo>(*metaData);
171 infoPtr->doInsert = false;
172 if (predicateColumn == RINGTONE_COLUMN_TITLE) {
173 infoMap[infoPtr->title].emplace_back(infoPtr);
174 } else {
175 infoMap[infoPtr->displayName].emplace_back(infoPtr);
176 }
177
178 RINGTONE_INFO_LOG("new info found in ringtone_lib: %{public}s", infoPtr->toString().c_str()); // debug
179 }
180
181 for (const auto& results : infoMap) {
182 if (!results.second.empty()) {
183 for (const auto& infoPtr : results.second) {
184 RINGTONE_INFO_LOG("key: %{public}s, value: %{public}s", results.first.c_str(),
185 infoPtr->toString().c_str());
186 }
187 } else {
188 RINGTONE_INFO_LOG("key: %{public}s, value is nullptr", results.first.c_str());
189 }
190 }
191
192 return E_SUCCESS;
193 }
194
AddSettingsToFileInfo(const DualFwkSettingItem & setting,FileInfo & info)195 static void AddSettingsToFileInfo(const DualFwkSettingItem &setting, FileInfo &info)
196 {
197 switch (setting.settingType) {
198 case TONE_SETTING_TYPE_ALARM:
199 info.toneType = TONE_TYPE_ALARM;
200 info.alarmToneType = setting.toneType;
201 info.alarmToneSourceType = SOURCE_TYPE_CUSTOMISED;
202 break;
203 case TONE_SETTING_TYPE_RINGTONE:
204 info.toneType = TONE_TYPE_RINGTONE;
205 info.ringToneType = setting.toneType;
206 info.ringToneSourceType = SOURCE_TYPE_CUSTOMISED;
207 break;
208 case TONE_SETTING_TYPE_SHOT:
209 info.toneType = TONE_TYPE_NOTIFICATION;
210 info.shotToneType = setting.toneType;
211 info.shotToneSourceType = SOURCE_TYPE_CUSTOMISED;
212 break;
213 case TONE_SETTING_TYPE_NOTIFICATION:
214 info.toneType = TONE_TYPE_NOTIFICATION;
215 info.notificationToneType = setting.toneType;
216 info.notificationToneSourceType = SOURCE_TYPE_CUSTOMISED;
217 break;
218 default:
219 break;
220 }
221 }
222
IsRingtoneConsistent(const std::shared_ptr<FileInfo> & ringtoneInfo,const DualFwkSettingItem & setting)223 bool IsRingtoneConsistent(const std::shared_ptr<FileInfo> &ringtoneInfo, const DualFwkSettingItem &setting)
224 {
225 auto keyToneType = setting.settingType;
226 return ((ringtoneInfo->toneType == ToneType::TONE_TYPE_ALARM &&
227 keyToneType == ToneSettingType::TONE_SETTING_TYPE_ALARM) ||
228 (ringtoneInfo->toneType == ToneType::TONE_TYPE_RINGTONE &&
229 keyToneType == ToneSettingType::TONE_SETTING_TYPE_RINGTONE) ||
230 (ringtoneInfo->toneType == ToneType::TONE_TYPE_NOTIFICATION &&
231 keyToneType == ToneSettingType::TONE_SETTING_TYPE_NOTIFICATION) ||
232 (ringtoneInfo->toneType == ToneType::TONE_TYPE_NOTIFICATION &&
233 keyToneType == ToneSettingType::TONE_SETTING_TYPE_SHOT));
234 }
235
GetRingtonebyDisplayName(std::vector<std::shared_ptr<FileInfo>> & results,const DualFwkSettingItem & setting,bool & doInsert)236 std::shared_ptr<FileInfo> GetRingtonebyDisplayName(std::vector<std::shared_ptr<FileInfo>>& results,
237 const DualFwkSettingItem &setting, bool &doInsert)
238 {
239 auto keyName = setting.toneFileName;
240 std::shared_ptr<FileInfo> infoPtr;
241 for (const auto& ringtoneInfo : results) {
242 if (ringtoneInfo == nullptr) {
243 RINGTONE_ERR_LOG("ringtoneInfo from ringtone by display name is nullptr");
244 continue;
245 }
246 if (ringtoneInfo->sourceType == SourceType::SOURCE_TYPE_PRESET) {
247 if (IsRingtoneConsistent(ringtoneInfo, setting)) {
248 infoPtr = ringtoneInfo;
249 RINGTONE_INFO_LOG("found %{public}s in ringtone db", keyName.c_str());
250 doInsert = false;
251 break;
252 } else {
253 RINGTONE_INFO_LOG("%{public}s is invalid", keyName.c_str());
254 continue;
255 }
256 } else {
257 infoPtr = ringtoneInfo;
258 RINGTONE_INFO_LOG("found %{public}s in ringtone db", keyName.c_str());
259 doInsert = false;
260 break;
261 }
262 }
263 return infoPtr;
264 }
265
GetRingtoneInfo(std::vector<std::shared_ptr<FileInfo>> & results,const DualFwkSettingItem & setting,bool & doInsert)266 std::shared_ptr<FileInfo> GetRingtoneInfo(std::vector<std::shared_ptr<FileInfo>>& results,
267 const DualFwkSettingItem &setting, bool &doInsert)
268 {
269 auto keyName = setting.toneFileName;
270 std::shared_ptr<FileInfo> infoPtr;
271 for (const auto& ringtoneInfo : results) {
272 if (ringtoneInfo == nullptr) {
273 RINGTONE_ERR_LOG("ringtoneInfo from ringtone by display name is nullptr");
274 continue;
275 }
276 infoPtr = ringtoneInfo;
277 RINGTONE_INFO_LOG("found %{public}s in ringtone db", keyName.c_str());
278 doInsert = false;
279 break;
280 }
281 return infoPtr;
282 }
283
MergeQueries(const DualFwkSettingItem & setting,std::map<std::string,std::shared_ptr<FileInfo>> resultFromFileMgr,std::map<std::string,std::vector<std::shared_ptr<FileInfo>>> resultFromRingtoneByDisplayName,bool & doInsert)284 static std::shared_ptr<FileInfo> MergeQueries(const DualFwkSettingItem &setting,
285 std::map<std::string, std::shared_ptr<FileInfo>> resultFromFileMgr,
286 std::map<std::string, std::vector<std::shared_ptr<FileInfo>>> resultFromRingtoneByDisplayName,
287 bool &doInsert)
288 {
289 std::shared_ptr<FileInfo> infoPtr;
290 std::vector<std::shared_ptr<FileInfo>> results;
291 doInsert = true;
292 auto keyName = setting.toneFileName;
293 if (resultFromFileMgr.find(keyName) != resultFromFileMgr.end()) {
294 infoPtr = resultFromFileMgr[keyName];
295 RINGTONE_INFO_LOG("found %{public}s in filemgr", keyName.c_str());
296 } else if (resultFromRingtoneByDisplayName.find(keyName) != resultFromRingtoneByDisplayName.end()) {
297 results = resultFromRingtoneByDisplayName.at(keyName);
298 if (results.empty()) {
299 RINGTONE_ERR_LOG("query ringtone from ringtoneDb by display name is null");
300 return nullptr;
301 }
302 infoPtr = GetRingtonebyDisplayName(results, setting, doInsert);
303 } else if (setting.isTitle) {
304 keyName = RingtoneUtils::ReplaceAll(keyName + ".ogg", " ", "_");
305 if (resultFromRingtoneByDisplayName.find(keyName) != resultFromRingtoneByDisplayName.end()) {
306 results = resultFromRingtoneByDisplayName.at(keyName);
307 if (results.empty()) {
308 RINGTONE_ERR_LOG("iquery ringtone from ringtoneDb by display name is null");
309 return nullptr;
310 }
311 infoPtr = GetRingtoneInfo(results, setting, doInsert);
312 }
313 } else {
314 RINGTONE_INFO_LOG("failed to find %{public}s", keyName.c_str());
315 }
316 return infoPtr;
317 }
318
BuildFileInfo()319 std::vector<FileInfo> RingtoneDualFwkRestore::BuildFileInfo()
320 {
321 std::vector<FileInfo> result;
322 std::map<std::string, std::shared_ptr<FileInfo>> resultFromFileMgr;
323 CustomisedToneProcessor customisedToneProcessor;
324 customisedToneProcessor.QueryFileMgrForFileInfo(resultFromFileMgr);
325
326 std::vector<std::string> displayNames = dualFwkSetting_->GetDisplayNames();
327 std::map<std::string, std::vector<std::shared_ptr<FileInfo>>> resultFromRingtoneByDisplayName;
328
329 QueryRingToneDbForFileInfo(GetBaseDb(), displayNames, resultFromRingtoneByDisplayName, "display_name");
330
331 for (const auto& setting : dualFwkSetting_->GetSettings()) {
332 bool doInsert = true;
333 auto infoPtr = MergeQueries(setting, resultFromFileMgr, resultFromRingtoneByDisplayName, doInsert);
334 if (infoPtr == nullptr) {
335 continue;
336 }
337 FileInfo info = *infoPtr;
338 info.doInsert = doInsert;
339 AddSettingsToFileInfo(setting, info);
340 result.push_back(info);
341
342 RINGTONE_INFO_LOG("push back into results -----> %{private}s", info.toString().c_str());
343 }
344 return result;
345 }
346
StartRestore()347 int32_t RingtoneDualFwkRestore::StartRestore()
348 {
349 if (dualFwkSetting_ == nullptr) {
350 RINGTONE_ERR_LOG("dualfwk restrore is not initialized successfully");
351 return E_ERR;
352 }
353 auto ret = RingtoneRestoreBase::StartRestore();
354 if (ret != E_OK) {
355 return ret;
356 }
357
358 std::vector<FileInfo> infos = BuildFileInfo();
359
360 if ((!infos.empty()) && (infos.size() != 0)) {
361 ret = InsertTones(infos);
362 }
363 FlushSettings();
364 return ret;
365 }
366
DupToneFile(FileInfo & info)367 int32_t RingtoneDualFwkRestore::DupToneFile(FileInfo &info)
368 {
369 RINGTONE_INFO_LOG("DupToneFile from %{private}s to %{private}s", info.data.c_str(), info.restorePath.c_str());
370 std::string absDstPath = info.restorePath;
371 RINGTONE_INFO_LOG("converted dst path from %{private}s to realpath %{private}s", info.restorePath.c_str(),
372 absDstPath.c_str());
373
374 std::string absSrcPath = info.data;
375
376 std::string::size_type isCustomisedToneFile = absSrcPath.find(FILE_MANAGER_BASE_PATH);
377 if (isCustomisedToneFile != std::string::npos) {
378 if (RingtoneFileUtils::CopyFileUtil(absSrcPath, absDstPath)) {
379 return E_SUCCESS;
380 }
381 RINGTONE_ERR_LOG("copy file fail, src: %{public}s, dest: %{public}s", absSrcPath.c_str(), absDstPath.c_str());
382 }
383
384 std::string sub = "cloud";
385 std::string replacement = "media/local";
386 auto found = absSrcPath.find(sub);
387 if (found != string::npos) {
388 absSrcPath.replace(found, sub.size(), replacement);
389 RINGTONE_INFO_LOG("converted src path from %{public}s to realpath %{public}s",
390 info.data.c_str(), absSrcPath.c_str());
391
392 if (!RingtoneFileUtils::CopyFileUtil(absSrcPath, absDstPath)) {
393 RINGTONE_ERR_LOG("copy-file failed, src: %{public}s, err: %{public}s", absSrcPath.c_str(),
394 strerror(errno));
395 return E_FAIL;
396 }
397 } else {
398 RINGTONE_INFO_LOG("no need to copy file.");
399 info.restorePath = absSrcPath;
400 }
401
402 return E_SUCCESS;
403 }
404
UpdateRestoreFileInfo(FileInfo & info)405 void RingtoneDualFwkRestore::UpdateRestoreFileInfo(FileInfo &info)
406 {
407 struct stat statInfo;
408 if (stat(info.restorePath.c_str(), &statInfo) != 0) {
409 RINGTONE_ERR_LOG("stat syscall err %{public}d", errno);
410 return;
411 }
412 info.dateModified = static_cast<int64_t>(RingtoneFileUtils::Timespec2Millisecond(statInfo.st_mtim));
413 info.displayName = RingtoneFileUtils::GetFileNameFromPath(info.restorePath);
414 }
415
OnPrepare(FileInfo & info,const std::string & dstPath)416 bool RingtoneDualFwkRestore::OnPrepare(FileInfo &info, const std::string &dstPath)
417 {
418 if (!RingtoneFileUtils::IsFileExists(dstPath)) {
419 RINGTONE_ERR_LOG("dst path is not existing, dst path=%{public}s", dstPath.c_str());
420 return false;
421 }
422 string fileName = RingtoneFileUtils::GetFileNameFromPath(info.data);
423 if (fileName.empty()) {
424 RINGTONE_ERR_LOG("src file name is null");
425 return false;
426 }
427 string baseName = RingtoneFileUtils::GetBaseNameFromPath(info.data);
428 if (baseName.empty()) {
429 RINGTONE_ERR_LOG("src file base name is null");
430 return false;
431 }
432
433 string extensionName = RingtoneFileUtils::GetExtensionFromPath(info.data);
434 int32_t repeatCount = 1;
435 info.restorePath = dstPath + "/" + fileName;
436 while (RingtoneFileUtils::IsFileExists(info.restorePath)) {
437 struct stat dstStatInfo {};
438 if (stat(info.restorePath.c_str(), &dstStatInfo) != 0) {
439 RINGTONE_ERR_LOG("Failed to get file %{private}s StatInfo, err=%{public}d",
440 info.restorePath.c_str(), errno);
441 return false;
442 }
443 if (info.size == dstStatInfo.st_size) {
444 CheckSetting(info);
445 RINGTONE_ERR_LOG("samefile: srcPath=%{private}s, dstPath=%{private}s", info.data.c_str(),
446 info.restorePath.c_str());
447 return false;
448 }
449 info.restorePath = dstPath + "/" + baseName + "(" + to_string(repeatCount++) + ")" + "." + extensionName;
450 }
451
452 if (DupToneFile(info) != E_SUCCESS) {
453 return false;
454 }
455
456 UpdateRestoreFileInfo(info);
457
458 return true;
459 }
460
OnFinished(vector<FileInfo> & infos)461 void RingtoneDualFwkRestore::OnFinished(vector<FileInfo> &infos)
462 {
463 RINGTONE_ERR_LOG("ringtone dualfwk restore finished");
464 }
465
LoadDualFwkConf(const std::string & backupPath)466 int32_t RingtoneDualFwkRestoreClone::LoadDualFwkConf(const std::string &backupPath)
467 {
468 DualFwkConfLoader confLoader;
469 if (confLoader.Init() != E_OK) {
470 RINGTONE_ERR_LOG("Failed to initialize DualFwkConfLoader.");
471 return E_FAIL;
472 }
473 DualFwkConf conf;
474 confLoader.Load(conf, RESTORE_SCENE_TYPE_DUAL_CLONE, backupPath);
475 confLoader.ShowConf(conf);
476
477 dualFwkSetting_ = std::make_unique<DualFwkSoundSetting>();
478 if (dualFwkSetting_ == nullptr) {
479 RINGTONE_ERR_LOG("Create DualFwkSoundSetting Failed.");
480 return E_FAIL;
481 }
482
483 dualFwkSetting_->ProcessConf(conf);
484 return E_SUCCESS;
485 }
486 } // namespace Media
487 } // namespace OHOS
488