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 "RingtoneDualfwRestore"
17
18 #include "ringtone_dualfw_restore.h"
19
20 #include <fcntl.h>
21 #include <sys/sendfile.h>
22 #include <sys/stat.h>
23
24 #include "datashare_helper.h"
25 #include "datashare_predicates.h"
26 #include "directory_ex.h"
27 #include "dualfw_conf_parser.h"
28 #include "dualfw_sound_setting.h"
29 #include "file_asset.h"
30 #include "fetch_result.h"
31 #include "iservice_registry.h"
32 #include "medialibrary_db_const.h"
33 #include "result_set_utils.h"
34 #include "ringtone_errno.h"
35 #include "ringtone_file_utils.h"
36 #include "ringtone_log.h"
37 #include "ringtone_restore_db_utils.h"
38 #include "ringtone_restore_base.h"
39 #include "ringtone_restore_type.h"
40 #include "ringtone_type.h"
41 #include "userfile_manager_types.h"
42
43 namespace OHOS {
44 namespace Media {
45 using namespace std;
46 static const mode_t MODE_RW_USR = 0644;
47 constexpr int STORAGE_MANAGER_MANAGER_ID = 5003;
48 static const string DUALFW_SOUND_CONF_XML = "setting_system.xml";
CreateMediaDataShare(int32_t systemAbilityId)49 static std::shared_ptr<DataShare::DataShareHelper> CreateMediaDataShare(int32_t systemAbilityId)
50 {
51 RINGTONE_INFO_LOG("CreateDataShareHelper::CreateFileExtHelper ");
52 auto saManager = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
53 if (saManager == nullptr) {
54 RINGTONE_ERR_LOG("CreateFileExtHelper Get system ability mgr failed.");
55 return nullptr;
56 }
57 auto remoteObj = saManager->GetSystemAbility(systemAbilityId);
58 if (remoteObj == nullptr) {
59 RINGTONE_ERR_LOG("CreateDataShareHelper GetSystemAbility Service Failed.");
60 return nullptr;
61 }
62 return DataShare::DataShareHelper::Creator(remoteObj, MEDIALIBRARY_DATA_URI);
63 }
64
ParseDualfwConf(string & xml)65 int32_t RingtoneDualfwRestore::ParseDualfwConf(string &xml)
66 {
67 auto parser = std::make_unique<DualfwConfParser>(xml);
68 if (parser == nullptr) {
69 RINGTONE_ERR_LOG("Create DualfwConfParser Failed.");
70 return E_FAIL;
71 }
72
73 dualfwSetting_ = std::make_unique<DualfwSoundSetting>();
74 if (dualfwSetting_ == nullptr) {
75 RINGTONE_ERR_LOG("Create DualfwSoundSetting Failed.");
76 return E_FAIL;
77 }
78
79 if (parser->Parse() != E_SUCCESS) {
80 RINGTONE_ERR_LOG("parse dualfw-sound-setting-xml Failed.");
81 return E_FAIL;
82 }
83
84 parser->ConfTraval([this](std::unique_ptr<DualFwConfRow> &conf) -> void {
85 dualfwSetting_->ProcessConfRow(conf);
86 });
87
88 return E_SUCCESS;
89 }
90
Init(const std::string & backupPath)91 int32_t RingtoneDualfwRestore::Init(const std::string &backupPath)
92 {
93 RINGTONE_INFO_LOG("Init db start");
94 if (backupPath.empty()) {
95 RINGTONE_ERR_LOG("error: backup path is null");
96 return E_INVALID_ARGUMENTS;
97 }
98 dualfwConf_ = backupPath + "/" + DUALFW_SOUND_CONF_XML;
99
100 if (!RingtoneFileUtils::IsFileExists(dualfwConf_)) {
101 RINGTONE_ERR_LOG("dualfw-conf-xml is not exist, path=%{public}s", dualfwConf_.c_str());
102 return E_FAIL;
103 }
104
105 mediaDataShare_ = CreateMediaDataShare(STORAGE_MANAGER_MANAGER_ID);
106 if (mediaDataShare_ == nullptr) {
107 RINGTONE_ERR_LOG("mediaDataShareHelper fail");
108 return E_FAIL;
109 }
110
111 if (ParseDualfwConf(dualfwConf_) != E_SUCCESS) {
112 return E_FAIL;
113 }
114
115 if (RingtoneRestoreBase::Init(backupPath) != E_OK) {
116 return E_FAIL;
117 }
118
119 RINGTONE_INFO_LOG("Init db successfully");
120 return E_OK;
121 }
122
MediaUriAppendKeyValue(string & uri,const string & key,const string & value)123 static void MediaUriAppendKeyValue(string &uri, const string &key, const string &value)
124 {
125 string uriKey = key + '=';
126 if (uri.find(uriKey) != string::npos) {
127 return;
128 }
129
130 char queryMark = (uri.find('?') == string::npos) ? '?' : '&';
131 string append = queryMark + key + '=' + value;
132
133 size_t posJ = uri.find('#');
134 if (posJ == string::npos) {
135 uri += append;
136 } else {
137 uri.insert(posJ, append);
138 }
139 }
140
141 static const string KEY_API_VERSION = "API_VERSION";
QueryMediaFileAsset(std::shared_ptr<DataShare::DataShareHelper> & mediaDataShare,DualfwSettingItem & item)142 static unique_ptr<FileAsset> QueryMediaFileAsset(std::shared_ptr<DataShare::DataShareHelper> &mediaDataShare,
143 DualfwSettingItem &item)
144 {
145 if (mediaDataShare == nullptr || item.toneFileName.empty() || item.toneFileName == "") {
146 RINGTONE_ERR_LOG("argument errr, return nullptr");
147 return nullptr;
148 }
149
150 vector<string> columns;
151 DataShare::DataSharePredicates predicates;
152 string prefix = MEDIA_DATA_DB_NAME + " = \"" + item.toneFileName + "\"";
153 predicates.SetWhereClause(prefix);
154 string queryFileUri = UFM_QUERY_AUDIO;
155 MediaUriAppendKeyValue(queryFileUri, KEY_API_VERSION, to_string(MEDIA_API_VERSION_V10));
156 shared_ptr<DataShare::DataShareResultSet> resultSet = nullptr;
157 Uri uri(queryFileUri);
158 resultSet = mediaDataShare->Query(uri, predicates, columns);
159 if (resultSet == nullptr) {
160 RINGTONE_INFO_LOG("query resultset is null");
161 return nullptr;
162 }
163
164 unique_ptr<FetchResult<FileAsset>> fetchFileResult = make_unique<FetchResult<FileAsset>>(move(resultSet));
165 if (fetchFileResult->GetCount() < 0) {
166 return nullptr;
167 }
168 unique_ptr<FileAsset> fileAsset = fetchFileResult->GetFirstObject();
169
170 return fileAsset;
171 }
172
BuildFileInfo(DualfwSettingItem & item,unique_ptr<FileAsset> & asset,FileInfo & info)173 static int32_t BuildFileInfo(DualfwSettingItem &item, unique_ptr<FileAsset> &asset, FileInfo &info)
174 {
175 if (asset == nullptr) {
176 return E_ERR;
177 }
178
179 switch (item.settingType) {
180 case TONE_SETTING_TYPE_ALARM:
181 info.toneType = TONE_TYPE_ALARM;
182 info.alarmToneType = item.toneType;
183 info.alarmToneSourceType = SOURCE_TYPE_CUSTOMISED;
184 break;
185 case TONE_SETTING_TYPE_RINGTONE:
186 info.toneType = TONE_TYPE_RINGTONE;
187 info.ringToneType = item.toneType;
188 info.ringToneSourceType = SOURCE_TYPE_CUSTOMISED;
189 break;
190 case TONE_SETTING_TYPE_SHOT:
191 info.toneType = TONE_TYPE_NOTIFICATION;
192 info.shotToneType = item.toneType;
193 info.shotToneSourceType = SOURCE_TYPE_CUSTOMISED;
194 break;
195 case TONE_SETTING_TYPE_NOTIFICATION:
196 info.toneType = TONE_TYPE_NOTIFICATION;
197 info.notificationToneType = item.toneType;
198 info.notificationToneSourceType = SOURCE_TYPE_CUSTOMISED;
199 break;
200 default:
201 break;
202 }
203
204 info.toneId = asset->GetId();
205 info.data = asset->GetPath();
206 info.size = asset->GetSize();
207 info.displayName = asset->GetDisplayName();
208 info.title = asset->GetTitle();
209 info.mimeType = asset->GetMimeType();
210 info.mediaType = RINGTONE_MEDIA_TYPE_AUDIO;
211 info.sourceType = SOURCE_TYPE_CUSTOMISED;
212 info.dateAdded = asset->GetDateAdded();
213 info.dateModified = asset->GetDateModified();
214 info.dateTaken = asset->GetDateTaken();
215 info.duration = asset->GetDuration();
216
217 return E_SUCCESS;
218 }
219
StartRestore()220 void RingtoneDualfwRestore::StartRestore()
221 {
222 if (dualfwSetting_ == nullptr || mediaDataShare_ == nullptr) {
223 RINGTONE_ERR_LOG("dualfw restrore is not initialized successfully");
224 return;
225 }
226
227 vector<FileInfo> infos = {};
228 dualfwSetting_->SettingsTraval([&](DualfwSettingItem &item) -> void {
229 auto asset = QueryMediaFileAsset(mediaDataShare_, item);
230 FileInfo info = {0};
231 auto ret = BuildFileInfo(item, asset, info);
232 if (ret == E_SUCCESS) {
233 infos.push_back(info);
234 }
235 RINGTONE_INFO_LOG("***************************************************");
236 RINGTONE_INFO_LOG("toneName = %{public}s", info.data.c_str());
237 RINGTONE_INFO_LOG("settingType = %{public}d", item.settingType);
238 RINGTONE_INFO_LOG("toneType = %{public}d", item.toneType);
239 RINGTONE_INFO_LOG("defaultSysSet = %{public}d", item.defaultSysSet);
240 RINGTONE_INFO_LOG("setFlag = %{public}d", item.setFlag);
241 });
242
243 if ((!infos.empty()) && (infos.size() != 0)) {
244 InsertTones(infos);
245 }
246 }
247
DupToneFile(FileInfo & info)248 int32_t RingtoneDualfwRestore::DupToneFile(FileInfo &info)
249 {
250 string uriStr = MEDIALIBRARY_DATA_URI + "/" + MEDIA_AUDIOOPRN + "/" + to_string(info.toneId);
251
252 Uri openFileUri(uriStr);
253 int32_t srcFd = mediaDataShare_->OpenFile(openFileUri, "r");
254 if (srcFd < 0) {
255 return E_ERR;
256 }
257
258 string absFilePath;
259 if (!PathToRealPath(info.restorePath, absFilePath)) {
260 RINGTONE_ERR_LOG("info.restorePath is not real path, file path: %{public}s", info.restorePath.c_str());
261 return E_ERR;
262 }
263 if (absFilePath.empty()) {
264 RINGTONE_ERR_LOG("Failed to obtain the canonical path for source path: %{public}s %{public}d",
265 absFilePath.c_str(), errno);
266 return E_ERR;
267 }
268
269 int32_t dstFd = open(absFilePath.c_str(), O_WRONLY | O_CREAT, MODE_RW_USR);
270 if (dstFd < 0) {
271 RINGTONE_ERR_LOG("Open file failed, errno:%{public}d", errno);
272 close(srcFd);
273 return E_ERR;
274 }
275 struct stat fst {};
276 if (fstat(srcFd, &fst) == 0) {
277 // Copy file content
278 if (sendfile(dstFd, srcFd, nullptr, fst.st_size) <= 0) {
279 RINGTONE_ERR_LOG("copy file failed errno:%{public}d", errno);
280 }
281 }
282 close(srcFd);
283 close(dstFd);
284
285 return E_SUCCESS;
286 }
287
UpdateRestoreFileInfo(FileInfo & info)288 void RingtoneDualfwRestore::UpdateRestoreFileInfo(FileInfo &info)
289 {
290 struct stat statInfo;
291 if (stat(info.restorePath.c_str(), &statInfo) != 0) {
292 RINGTONE_ERR_LOG("stat syscall err %{public}d", errno);
293 return;
294 }
295 info.dateModified = static_cast<int64_t>(RingtoneFileUtils::Timespec2Millisecond(statInfo.st_mtim));
296 info.displayName = RingtoneFileUtils::GetFileNameFromPath(info.restorePath);
297 }
298
OnPrepare(FileInfo & info,const std::string & dstPath)299 bool RingtoneDualfwRestore::OnPrepare(FileInfo &info, const std::string &dstPath)
300 {
301 if (!RingtoneFileUtils::IsFileExists(dstPath)) {
302 RINGTONE_ERR_LOG("dst path is not existing, dst path=%{public}s", dstPath.c_str());
303 return false;
304 }
305 string fileName = RingtoneFileUtils::GetFileNameFromPath(info.data);
306 if (fileName.empty() || fileName == "") {
307 RINGTONE_ERR_LOG("src file name is null");
308 return false;
309 }
310 string baseName = RingtoneFileUtils::GetBaseNameFromPath(info.data);
311 if (baseName.empty() || baseName == "") {
312 RINGTONE_ERR_LOG("src file base name is null");
313 return false;
314 }
315
316 string extensionName = RingtoneFileUtils::GetExtensionFromPath(info.data);
317 int32_t repeatCount = 1;
318 while (RingtoneFileUtils::IsFileExists(dstPath + "/" + fileName)) {
319 struct stat dstStatInfo {};
320 string dstName = dstPath + "/" + fileName;
321 if (stat(dstName.c_str(), &dstStatInfo) != 0) {
322 RINGTONE_ERR_LOG("Failed to get file %{private}s StatInfo, err=%{public}d", dstName.c_str(), errno);
323 return false;
324 }
325 if (info.size == dstStatInfo.st_size) {
326 RINGTONE_ERR_LOG("samefile: srcPath=%{public}s, dstPath=%{public}s", info.data.c_str(),
327 (dstPath + "/" + fileName).c_str());
328 return false;
329 }
330 fileName = baseName + "(" + to_string(repeatCount++) + ")" + "." + extensionName;
331 }
332 info.restorePath = dstPath + "/" + fileName;
333
334 if (DupToneFile(info) != E_SUCCESS) {
335 return false;
336 }
337
338 UpdateRestoreFileInfo(info);
339
340 return true;
341 }
342
OnFinished(vector<FileInfo> & infos)343 void RingtoneDualfwRestore::OnFinished(vector<FileInfo> &infos)
344 {
345 RINGTONE_ERR_LOG("ringtone dualfw restore finished");
346 }
347 } // namespace Media
348 } // namespace OHOS
349