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