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