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