• 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 "Scanner"
17 
18 #include "ringtone_scanner.h"
19 
20 #include "dfx_const.h"
21 #include "directory_ex.h"
22 #include "parameter.h"
23 #include "preferences_helper.h"
24 #include "ringtone_default_setting.h"
25 #include "ringtone_file_utils.h"
26 #include "ringtone_log.h"
27 #include "ringtone_mimetype_utils.h"
28 #include "ringtone_rdbstore.h"
29 #include "ringtone_scanner_utils.h"
30 
31 namespace OHOS {
32 namespace Media {
33 using namespace std;
34 using namespace OHOS::AppExecFwk;
35 using namespace OHOS::DataShare;
36 static const int32_t SCANNER_WAIT_FOR_TIMEOUT = 10000; // ms
37 static const std::string PATH_PLAY_MODE_SYNC = "/synchronized";
38 static const std::string PATH_PLAY_MODE_CLASSIC = "/non-synchronized";
39 static const std::string PATH_VIBRATE_TYPE_STANDARD = "/standard";
40 static const std::string PATH_VIBRATE_TYPE_GENTLE = "/gentle";
41 static const std::string ALARMS_TYPE = "alarms";
42 static const std::string RINGTONES_TYPE = "ringtones";
43 static const std::string NOTIFICATIONS_TYPE = "notifications";
44 static const char RINGTONE_RDB_SCANNER_FLAG_KEY[] = "RDBInitScanner";
45 static const int RINGTONE_RDB_SCANNER_FLAG_KEY_TRUE = 1;
46 static const int RINGTONE_RDB_SCANNER_FLAG_KEY_FALSE = 0;
47 static const char RINGTONE_PARAMETER_SCANNER_FIRST_KEY[] = "ringtone.scanner.first";
48 static const char RINGTONE_PARAMETER_SCANNER_FIRST_TRUE[] = "true";
49 
50 static std::unordered_map<std::string, std::pair<int32_t, int32_t>> g_typeMap = {
51     // customized tones map
52     {RINGTONE_CUSTOMIZED_ALARM_PATH, {SOURCE_TYPE_CUSTOMISED, TONE_TYPE_ALARM}},
53     {RINGTONE_CUSTOMIZED_RINGTONE_PATH, {SOURCE_TYPE_CUSTOMISED, TONE_TYPE_RINGTONE}},
54     {RINGTONE_CUSTOMIZED_NOTIFICATIONS_PATH, {SOURCE_TYPE_CUSTOMISED, TONE_TYPE_NOTIFICATION}},
55     {RINGTONE_CUSTOMIZED_CONTACTS_PATH, {SOURCE_TYPE_CUSTOMISED, TONE_TYPE_CONTACTS}},
56     // customized tones map
57     {ROOT_TONE_PRELOAD_PATH_NOAH_PATH + "/alarms", {SOURCE_TYPE_PRESET, TONE_TYPE_ALARM}},
58     {ROOT_TONE_PRELOAD_PATH_NOAH_PATH + "/ringtones", {SOURCE_TYPE_PRESET, TONE_TYPE_RINGTONE}},
59     {ROOT_TONE_PRELOAD_PATH_NOAH_PATH + "/notifications", {SOURCE_TYPE_PRESET, TONE_TYPE_NOTIFICATION}},
60     {ROOT_TONE_PRELOAD_PATH_CHINA_PATH + "/alarms", {SOURCE_TYPE_PRESET, TONE_TYPE_ALARM}},
61     {ROOT_TONE_PRELOAD_PATH_CHINA_PATH + "/ringtones", {SOURCE_TYPE_PRESET, TONE_TYPE_RINGTONE}},
62     {ROOT_TONE_PRELOAD_PATH_CHINA_PATH + "/notifications", {SOURCE_TYPE_PRESET, TONE_TYPE_NOTIFICATION}},
63     {ROOT_TONE_PRELOAD_PATH_OVERSEA_PATH + "/alarms", {SOURCE_TYPE_PRESET, TONE_TYPE_ALARM}},
64     {ROOT_TONE_PRELOAD_PATH_OVERSEA_PATH + "/ringtones", {SOURCE_TYPE_PRESET, TONE_TYPE_RINGTONE}},
65     {ROOT_TONE_PRELOAD_PATH_OVERSEA_PATH + "/notifications", {SOURCE_TYPE_PRESET, TONE_TYPE_NOTIFICATION}},
66 };
67 // vibrate type map
68 static std::unordered_map<std::string, std::pair<int32_t, int32_t>> g_vibrateTypeMap = {
69     {ROOT_VIBRATE_PRELOAD_PATH_NOAH_PATH + PATH_VIBRATE_TYPE_STANDARD, {SOURCE_TYPE_PRESET, VIBRATE_TYPE_STANDARD}},
70     {ROOT_VIBRATE_PRELOAD_PATH_NOAH_PATH + PATH_VIBRATE_TYPE_GENTLE, {SOURCE_TYPE_PRESET, VIBRATE_TYPE_GENTLE}},
71     {ROOT_VIBRATE_PRELOAD_PATH_CHINA_PATH + PATH_VIBRATE_TYPE_STANDARD, {SOURCE_TYPE_PRESET, VIBRATE_TYPE_STANDARD}},
72     {ROOT_VIBRATE_PRELOAD_PATH_CHINA_PATH + PATH_VIBRATE_TYPE_GENTLE, {SOURCE_TYPE_PRESET, VIBRATE_TYPE_GENTLE}},
73     {ROOT_VIBRATE_PRELOAD_PATH_OVERSEA_PATH + PATH_VIBRATE_TYPE_STANDARD, {SOURCE_TYPE_PRESET, VIBRATE_TYPE_STANDARD}},
74     {ROOT_VIBRATE_PRELOAD_PATH_OVERSEA_PATH + PATH_VIBRATE_TYPE_GENTLE, {SOURCE_TYPE_PRESET, VIBRATE_TYPE_GENTLE}},
75 };
76 
77 static std::unordered_map<std::string, std::pair<int32_t, int32_t>> g_vibratePlayModeMap = {
78     {ROOT_VIBRATE_PRELOAD_PATH_NOAH_PATH + PATH_VIBRATE_TYPE_STANDARD + PATH_PLAY_MODE_SYNC,
79         {SOURCE_TYPE_PRESET, VIBRATE_PLAYMODE_SYNC}},
80     {ROOT_VIBRATE_PRELOAD_PATH_NOAH_PATH + PATH_VIBRATE_TYPE_STANDARD + PATH_PLAY_MODE_CLASSIC,
81         {SOURCE_TYPE_PRESET, VIBRATE_PLAYMODE_CLASSIC}},
82     {ROOT_VIBRATE_PRELOAD_PATH_NOAH_PATH + PATH_VIBRATE_TYPE_GENTLE + PATH_PLAY_MODE_SYNC,
83         {SOURCE_TYPE_PRESET, VIBRATE_PLAYMODE_SYNC}},
84     {ROOT_VIBRATE_PRELOAD_PATH_NOAH_PATH + PATH_VIBRATE_TYPE_GENTLE + PATH_PLAY_MODE_CLASSIC,
85         {SOURCE_TYPE_PRESET, VIBRATE_PLAYMODE_CLASSIC}},
86     {ROOT_VIBRATE_PRELOAD_PATH_CHINA_PATH + PATH_VIBRATE_TYPE_STANDARD + PATH_PLAY_MODE_SYNC,
87         {SOURCE_TYPE_PRESET, VIBRATE_PLAYMODE_SYNC}},
88     {ROOT_VIBRATE_PRELOAD_PATH_CHINA_PATH + PATH_VIBRATE_TYPE_STANDARD + PATH_PLAY_MODE_CLASSIC,
89         {SOURCE_TYPE_PRESET, VIBRATE_PLAYMODE_CLASSIC}},
90     {ROOT_VIBRATE_PRELOAD_PATH_CHINA_PATH + PATH_VIBRATE_TYPE_GENTLE + PATH_PLAY_MODE_SYNC,
91         {SOURCE_TYPE_PRESET, VIBRATE_PLAYMODE_SYNC}},
92     {ROOT_VIBRATE_PRELOAD_PATH_CHINA_PATH + PATH_VIBRATE_TYPE_GENTLE + PATH_PLAY_MODE_CLASSIC,
93         {SOURCE_TYPE_PRESET, VIBRATE_PLAYMODE_CLASSIC}},
94     {ROOT_VIBRATE_PRELOAD_PATH_OVERSEA_PATH + PATH_VIBRATE_TYPE_STANDARD + PATH_PLAY_MODE_SYNC,
95         {SOURCE_TYPE_PRESET, VIBRATE_PLAYMODE_SYNC}},
96     {ROOT_VIBRATE_PRELOAD_PATH_OVERSEA_PATH + PATH_VIBRATE_TYPE_STANDARD + PATH_PLAY_MODE_CLASSIC,
97         {SOURCE_TYPE_PRESET, VIBRATE_PLAYMODE_CLASSIC}},
98     {ROOT_VIBRATE_PRELOAD_PATH_OVERSEA_PATH + PATH_VIBRATE_TYPE_GENTLE + PATH_PLAY_MODE_SYNC,
99         {SOURCE_TYPE_PRESET, VIBRATE_PLAYMODE_SYNC}},
100     {ROOT_VIBRATE_PRELOAD_PATH_OVERSEA_PATH + PATH_VIBRATE_TYPE_GENTLE + PATH_PLAY_MODE_CLASSIC,
101         {SOURCE_TYPE_PRESET, VIBRATE_PLAYMODE_CLASSIC}},
102 };
103 
104 static const std::vector<std::string> g_preloadDirs = {
105     {ROOT_TONE_PRELOAD_PATH_NOAH_PATH + "/alarms"},
106     {ROOT_TONE_PRELOAD_PATH_NOAH_PATH + "/ringtones"},
107     {ROOT_TONE_PRELOAD_PATH_NOAH_PATH + "/notifications"},
108     {ROOT_TONE_PRELOAD_PATH_CHINA_PATH + "/alarms"},
109     {ROOT_TONE_PRELOAD_PATH_CHINA_PATH + "/ringtones"},
110     {ROOT_TONE_PRELOAD_PATH_CHINA_PATH + "/notifications"},
111     {ROOT_TONE_PRELOAD_PATH_OVERSEA_PATH + "/alarms"},
112     {ROOT_TONE_PRELOAD_PATH_OVERSEA_PATH + "/ringtones"},
113     {ROOT_TONE_PRELOAD_PATH_OVERSEA_PATH + "/notifications"},
114     {ROOT_VIBRATE_PRELOAD_PATH_NOAH_PATH + "/standard"},
115     {ROOT_VIBRATE_PRELOAD_PATH_NOAH_PATH + "/gentle"},
116     {ROOT_VIBRATE_PRELOAD_PATH_CHINA_PATH + "/standard"},
117     {ROOT_VIBRATE_PRELOAD_PATH_CHINA_PATH + "/gentle"},
118     {ROOT_VIBRATE_PRELOAD_PATH_OVERSEA_PATH + "/standard"},
119     {ROOT_VIBRATE_PRELOAD_PATH_OVERSEA_PATH + "/gentle"},
120 };
121 
RingtoneScannerObj(const std::string & path,const std::shared_ptr<IRingtoneScannerCallback> & callback,RingtoneScannerObj::ScanType type)122 RingtoneScannerObj::RingtoneScannerObj(const std::string &path,
123     const std::shared_ptr<IRingtoneScannerCallback> &callback,
124     RingtoneScannerObj::ScanType type) : type_(type), callback_(callback)
125 {
126     if (type_ == DIRECTORY) {
127         dir_ = path;
128     } else if (type_ == FILE) {
129         path_ = path;
130     }
131     // when path is /Photo, it means update or clone scene
132     stopFlag_ = make_shared<bool>(false);
133 }
134 
RingtoneScannerObj(RingtoneScannerObj::ScanType type)135 RingtoneScannerObj::RingtoneScannerObj(RingtoneScannerObj::ScanType type) : type_(type)
136 {
137     stopFlag_ = make_shared<bool>(false);
138 }
139 
SetStopFlag(std::shared_ptr<bool> & flag)140 void RingtoneScannerObj::SetStopFlag(std::shared_ptr<bool> &flag)
141 {
142     stopFlag_ = flag;
143 }
144 
ScanFile()145 int32_t RingtoneScannerObj::ScanFile()
146 {
147     RINGTONE_DEBUG_LOG("scan file %{private}s", path_.c_str());
148 
149     int32_t ret = ScanFileInternal();
150     if (ret != E_OK) {
151         RINGTONE_ERR_LOG("ScanFileInternal err %{public}d", ret);
152     }
153 
154     (void)InvokeCallback(ret);
155 
156     return ret;
157 }
158 
InvokeCallback(int32_t err)159 int32_t RingtoneScannerObj::InvokeCallback(int32_t err)
160 {
161     if (callback_ == nullptr) {
162         return E_OK;
163     }
164 
165     return callback_->OnScanFinished(err, uri_, path_);
166 }
167 
Scan()168 void RingtoneScannerObj::Scan()
169 {
170     switch (type_) {
171         case FILE:
172             ScanFile();
173             break;
174         case DIRECTORY:
175             ScanDir();
176             break;
177         case START:
178             BootScan();
179             break;
180         default:
181             break;
182     }
183 }
184 
UpdateDefaultTone()185 int32_t RingtoneScannerObj::UpdateDefaultTone()
186 {
187     auto rdbStore = RingtoneRdbStore::GetInstance();
188     CHECK_AND_RETURN_RET_LOG(rdbStore != nullptr, E_ERR, "rdbStore is nullptr");
189     auto rawRdb = rdbStore->GetRaw();
190     CHECK_AND_RETURN_RET_LOG(rawRdb != nullptr, E_ERR, "rawRdb is nullptr");
191     int errCode = 0;
192     shared_ptr<NativePreferences::Preferences> prefs =
193         NativePreferences::PreferencesHelper::GetPreferences(COMMON_XML_EL1, errCode);
194     CHECK_AND_RETURN_RET_LOG(prefs, E_ERR, "Preferences is null");
195     int isScanner = prefs->GetInt(RINGTONE_RDB_SCANNER_FLAG_KEY, RINGTONE_RDB_SCANNER_FLAG_KEY_FALSE);
196     if (isScanner == RINGTONE_RDB_SCANNER_FLAG_KEY_TRUE) {
197         RingtoneDefaultSetting::GetObj(rawRdb)->UpdateDefaultSystemTone();
198         RINGTONE_INFO_LOG("The default ringtone has been set, no need to be configured again");
199         return E_OK;
200     }
201     // reset ringtone default settings
202     RingtoneDefaultSetting::GetObj(rawRdb)->Update();
203     RingtoneDefaultSetting::GetObj(rawRdb)->UpdateDefaultSystemTone();
204     prefs->PutInt(RINGTONE_RDB_SCANNER_FLAG_KEY, RINGTONE_RDB_SCANNER_FLAG_KEY_TRUE);
205     prefs->FlushSync();
206     return E_OK;
207 }
208 
BootScanProcess()209 int32_t RingtoneScannerObj::BootScanProcess()
210 {
211     int64_t scanStart = RingtoneFileUtils::UTCTimeMilliSeconds();
212     int32_t ret = E_OK;
213     bool res = true;
214     res = RingtoneScannerDb::UpdateScannerFlag();
215     CHECK_AND_RETURN_RET_LOG(res, E_HAS_DB_ERROR, "UpdateScannerFlag operation failed, res: %{public}d",
216         E_HAS_DB_ERROR);
217     for (auto &dir : g_preloadDirs) {
218         RINGTONE_INFO_LOG("start to scan realpath %{private}s", dir.c_str());
219         string realPath;
220         if (!PathToRealPath(dir, realPath)) {
221             RINGTONE_INFO_LOG("failed to get realpath %{private}s, errno %{public}d", dir.c_str(), errno);
222             continue;
223         }
224 
225         RINGTONE_INFO_LOG("start to scan realpath %{private}s", dir.c_str());
226         callback_ = make_shared<ScanErrCallback>(dir);
227 
228         if (RingtoneScannerUtils::IsDirectory(realPath)) {
229             dir_ = move(realPath);
230             ret = ScanDir();
231         } else if (RingtoneScannerUtils::IsRegularFile(realPath)) {
232             path_ = move(realPath);
233             ret = ScanFile();
234         }
235         CHECK_AND_RETURN_RET_LOG(ret == E_OK, ret, "BootScan err, ret: %{public}d", ret);
236     }
237 
238     ret = UpdateDefaultTone();
239     CHECK_AND_RETURN_RET_LOG(ret == E_OK, ret, "UpdateDefaultTone operation failed, ret: %{public}d", ret);
240 
241     int64_t scanEnd = RingtoneFileUtils::UTCTimeMilliSeconds();
242     RINGTONE_INFO_LOG("total preload tone files count:%{public}d, scanned: %{public}d, costed-time:%{public}"
243         PRId64 " ms", tonesScannedCount_, tonesScannedCount_, scanEnd - scanStart);
244     res = RingtoneScannerDb::DeleteNotExist();
245     CHECK_AND_RETURN_RET_LOG(res, E_ERR, "DeleteNotExist operation failed, res: %{public}d", res);
246     return ret;
247 }
248 
BootScan()249 int32_t RingtoneScannerObj::BootScan()
250 {
251     RINGTONE_INFO_LOG("start to BootScan");
252     int32_t ret = BootScanProcess();
253     unique_lock<mutex> lock(scannerLock_);
254     scannerCv_.notify_one();
255     if (ret == E_OK) {
256         int result = SetParameter(RINGTONE_PARAMETER_SCANNER_FIRST_KEY, RINGTONE_PARAMETER_SCANNER_FIRST_TRUE);
257         RINGTONE_INFO_LOG("SetParameter scan end, result: %{public}d", result);
258     }
259     return ret;
260 }
261 
WaitFor()262 void RingtoneScannerObj::WaitFor()
263 {
264     unique_lock<mutex> lock(scannerLock_);
265     scannerCv_.wait_for(lock, chrono::milliseconds(SCANNER_WAIT_FOR_TIMEOUT));
266 }
267 
ScanDir()268 int32_t RingtoneScannerObj::ScanDir()
269 {
270     RINGTONE_INFO_LOG("scan dir %{private}s", dir_.c_str());
271 
272     int32_t ret = ScanDirInternal();
273     if (ret != E_OK) {
274         RINGTONE_ERR_LOG("ScanDirInternal err %{public}d", ret);
275     }
276 
277     (void)InvokeCallback(ret);
278 
279     return ret;
280 }
281 
ScanDirInternal()282 int32_t RingtoneScannerObj::ScanDirInternal()
283 {
284     if (RingtoneScannerUtils::IsDirHiddenRecursive(dir_)) {
285         RINGTONE_ERR_LOG("the dir %{private}s is hidden", dir_.c_str());
286         return E_DIR_HIDDEN;
287     }
288 
289     /* no further operation when stopped */
290     auto err = WalkFileTree(dir_);
291     if (err != E_OK) {
292         RINGTONE_ERR_LOG("walk file tree err %{public}d", err);
293         return err;
294     }
295     err = CommitTransaction();
296     if (err != E_OK) {
297         RINGTONE_ERR_LOG("commit transaction err %{public}d", err);
298         return err;
299     }
300 
301     err = CommitVibrateTransaction();
302     if (err != E_OK) {
303         RINGTONE_ERR_LOG("commit vibrate transaction err %{public}d", err);
304         return err;
305     }
306     err = CleanupDirectory();
307     if (err != E_OK) {
308         RINGTONE_ERR_LOG("clean up dir err %{public}d", err);
309         return err;
310     }
311 
312     return E_OK;
313 }
314 
CleanupDirectory()315 int32_t RingtoneScannerObj::CleanupDirectory()
316 {
317     return E_OK;
318 }
319 
CommitTransaction()320 int32_t RingtoneScannerObj::CommitTransaction()
321 {
322     unique_ptr<RingtoneMetadata> data;
323     string tableName = RINGTONE_TABLE;
324 
325     // will begin a transaction in later pr
326     for (uint32_t i = 0; i < dataBuffer_.size(); i++) {
327         data = move(dataBuffer_[i]);
328         if (data->GetToneId() != FILE_ID_DEFAULT) {
329             RingtoneScannerDb::UpdateMetadata(*data, tableName);
330         } else {
331             RingtoneScannerDb::InsertMetadata(*data, tableName);
332         }
333     }
334 
335     if (dataBuffer_.size() > 0) {
336         tonesScannedCount_ += dataBuffer_.size();
337     }
338     dataBuffer_.clear();
339 
340     return E_OK;
341 }
342 
CommitVibrateTransaction()343 int32_t RingtoneScannerObj::CommitVibrateTransaction()
344 {
345     unique_ptr<VibrateMetadata> vibrateData;
346     string vibrateTableName = VIBRATE_TABLE;
347 
348     for (uint32_t i = 0; i < vibrateDataBuffer_.size(); i++) {
349         vibrateData = move(vibrateDataBuffer_[i]);
350         if (vibrateData->GetVibrateId() != FILE_ID_DEFAULT) {
351             RingtoneScannerDb::UpdateVibrateMetadata(*vibrateData, vibrateTableName);
352         } else {
353             RingtoneScannerDb::InsertVibrateMetadata(*vibrateData, vibrateTableName);
354         }
355     }
356 
357     if (vibrateDataBuffer_.size() > 0) {
358         tonesScannedCount_ += vibrateDataBuffer_.size();
359     }
360     vibrateDataBuffer_.clear();
361 
362     return E_OK;
363 }
364 
WalkFileTree(const string & path)365 int32_t RingtoneScannerObj::WalkFileTree(const string &path)
366 {
367     int err = E_OK;
368     DIR *dirPath = nullptr;
369     struct dirent *ent = nullptr;
370     size_t len = path.length();
371     struct stat statInfo;
372     if (len >= FILENAME_MAX - 1) {
373         return ERR_INCORRECT_PATH;
374     }
375     auto fName = (char *)calloc(FILENAME_MAX, sizeof(char));
376     if (fName == nullptr) {
377         return E_NO_MEMORY;
378     }
379     if (strcpy_s(fName, FILENAME_MAX, path.c_str()) != ERR_SUCCESS) {
380         free(fName);
381         return E_ERR;
382     }
383     fName[len++] = '/';
384     if ((dirPath = opendir(path.c_str())) == nullptr) {
385         free(fName);
386         return E_PERMISSION_DENIED;
387     }
388     while ((ent = readdir(dirPath)) != nullptr) {
389         if (*stopFlag_) {
390             err = E_STOP;
391             break;
392         }
393         if (!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, "..")) {
394             continue;
395         }
396         if (strncpy_s(fName + len, FILENAME_MAX - len, ent->d_name, FILENAME_MAX - len)) {
397             RINGTONE_ERR_LOG("Failed to copy file name %{private}s", fName);
398             continue;
399         }
400         if (lstat(fName, &statInfo) == -1) {
401             RINGTONE_ERR_LOG("Failed to get info of directory %{private}s", fName);
402             continue;
403         }
404         string currentPath = fName;
405         if (S_ISDIR(statInfo.st_mode)) {
406             if (RingtoneScannerUtils::IsDirHidden(currentPath)) {
407                 continue;
408             }
409             (void)WalkFileTree(currentPath);
410         } else {
411             (void)ScanFileInTraversal(currentPath);
412         }
413     }
414     closedir(dirPath);
415     free(fName);
416     return err;
417 }
418 
ScanFileInTraversal(const string & path)419 int32_t RingtoneScannerObj::ScanFileInTraversal(const string &path)
420 {
421     path_ = path;
422     if (RingtoneScannerUtils::IsFileHidden(path_)) {
423         RINGTONE_ERR_LOG("the file is hidden");
424         return E_FILE_HIDDEN;
425     }
426 
427     bool flag = (path_.find(ROOT_VIBRATE_PRELOAD_PATH_NOAH_PATH) != std::string::npos) ? true : false;
428     flag |= (path_.find(ROOT_VIBRATE_PRELOAD_PATH_CHINA_PATH) != std::string::npos);
429     flag |= (path_.find(ROOT_VIBRATE_PRELOAD_PATH_OVERSEA_PATH) != std::string::npos);
430     std::string extension = RingtoneScannerUtils::GetFileExtension(path_);
431 
432     if (flag) {
433         if (extension.compare("json") == 0) {
434             isVibrateFile_ = true;
435             return ScanVibrateFile();
436         }
437         return E_OK;
438     }
439 
440     int32_t err = GetFileMetadata();
441     if (err != E_OK) {
442         if (err != E_SCANNED) {
443             RINGTONE_ERR_LOG("failed to get file metadata");
444         }
445         return err;
446     }
447 
448     err = BuildFileInfo();
449     if (err != E_OK) {
450         RINGTONE_ERR_LOG("failed to get other file metadata");
451         return err;
452     }
453 
454     return E_OK;
455 }
456 
GetFileMetadata()457 int32_t RingtoneScannerObj::GetFileMetadata()
458 {
459     if (path_.empty()) {
460         return E_INVALID_ARGUMENTS;
461     }
462     struct stat statInfo = { 0 };
463     if (stat(path_.c_str(), &statInfo) != 0) {
464         RINGTONE_ERR_LOG("stat syscall err %{public}d", errno);
465         return E_SYSCALL;
466     }
467 
468     int errCode = 0;
469     if (isVibrateFile_) {
470         errCode = BuildVibrateData(statInfo);
471         if (errCode != E_OK) {
472             return errCode;
473         }
474     } else {
475         errCode = BuildData(statInfo);
476         if (errCode != E_OK) {
477             return errCode;
478         }
479     }
480 
481     return E_OK;
482 }
483 
BuildFileInfo()484 int32_t RingtoneScannerObj::BuildFileInfo()
485 {
486     auto err = GetMediaInfo();
487     if (err != E_OK) {
488         RINGTONE_ERR_LOG("failed to get media info");
489     }
490 
491     err = AddToTransaction();
492     if (err != E_OK) {
493         RINGTONE_ERR_LOG("failed to add to transaction err %{public}d", err);
494         return err;
495     }
496 
497     return E_OK;
498 }
499 
AddToTransaction()500 int32_t RingtoneScannerObj::AddToTransaction()
501 {
502     if (isVibrateFile_) {
503         vibrateDataBuffer_.emplace_back(move(vibrateData_));
504         if (vibrateDataBuffer_.size() >= MAX_BATCH_SIZE) {
505             return CommitVibrateTransaction();
506         }
507     } else {
508         dataBuffer_.emplace_back(move(data_));
509         if (dataBuffer_.size() >= MAX_BATCH_SIZE) {
510             return CommitTransaction();
511         }
512     }
513 
514     return E_OK;
515 }
516 
GetMediaInfo()517 int32_t RingtoneScannerObj::GetMediaInfo()
518 {
519 #ifdef ENABLE_METADATA_EXTRACTOR
520     auto pos = data_->GetMimeType().find_first_of("/");
521     std::string mimePrefix = data_->GetMimeType().substr(0, pos) + "/*";
522     if (find(EXTRACTOR_SUPPORTED_MIME.begin(), EXTRACTOR_SUPPORTED_MIME.end(), mimePrefix) !=
523         EXTRACTOR_SUPPORTED_MIME.end()) {
524         return RingtoneMetadataExtractor::Extract(data_);
525     }
526 #endif // ENABLE_METADATA_EXTRACTOR
527     return E_OK;
528 }
529 
BuildData(const struct stat & statInfo)530 int32_t RingtoneScannerObj::BuildData(const struct stat &statInfo)
531 {
532     data_ = make_unique<RingtoneMetadata>();
533     if (data_ == nullptr) {
534         RINGTONE_ERR_LOG("failed to make unique ptr for metadata");
535         return E_DATA;
536     }
537 
538     if (S_ISDIR(statInfo.st_mode)) {
539         return E_INVALID_ARGUMENTS;
540     }
541 
542     int32_t err = RingtoneScannerDb::GetFileBasicInfo(path_, data_);
543     if (err != E_OK) {
544         RINGTONE_ERR_LOG("failed to get file basic info");
545         return err;
546     }
547 
548     for (const auto& pair : g_typeMap) {
549         if (path_.find(pair.first) == 0) {
550             data_->SetSourceType(pair.second.first);
551             data_->SetToneType(pair.second.second);
552         }
553     }
554 
555     // file path
556     data_->SetData(path_);
557     auto dispName = RingtoneScannerUtils::GetFileNameFromUri(path_);
558     data_->SetDisplayName(dispName);
559     if (data_->GetTitle() == TITLE_DEFAULT) {
560         data_->SetTitle(RingtoneScannerUtils::GetFileTitle(data_->GetDisplayName()));
561     }
562 
563     // statinfo
564     data_->SetSize(statInfo.st_size);
565     data_->SetDateModified(static_cast<int64_t>(RingtoneFileUtils::Timespec2Millisecond(statInfo.st_mtim)));
566 
567     // extension and type
568     std::string extension = RingtoneScannerUtils::GetFileExtension(path_);
569     std::string mimeType = RingtoneMimeTypeUtils::GetMimeTypeFromExtension(extension);
570     data_->SetMimeType(mimeType);
571     int32_t mime = RingtoneMimeTypeUtils::GetMediaTypeFromMimeType(mimeType);
572     data_->SetMediaType(mime);
573 
574     return E_OK;
575 }
576 
BuildVibrateData(const struct stat & statInfo)577 int32_t RingtoneScannerObj::BuildVibrateData(const struct stat &statInfo)
578 {
579     vibrateData_ = make_unique<VibrateMetadata>();
580     if (vibrateData_ == nullptr) {
581         RINGTONE_ERR_LOG("failed to make unique ptr for metadata");
582         return E_DATA;
583     }
584 
585     if (S_ISDIR(statInfo.st_mode)) {
586         return E_INVALID_ARGUMENTS;
587     }
588 
589     int32_t err = RingtoneScannerDb::GetVibrateFileBasicInfo(path_, vibrateData_);
590     if (err != E_OK) {
591         RINGTONE_ERR_LOG("failed to get file basic info");
592         return err;
593     }
594 
595     for (const auto &pair : g_vibrateTypeMap) {
596         if (path_.find(pair.first) == 0) {
597             vibrateData_->SetSourceType(pair.second.first);
598             vibrateData_->SetVibrateType(pair.second.second);
599             int32_t ntype = 0;
600             if (pair.second.second == VIBRATE_TYPE_STANDARD) {
601                 ntype = (path_.find(ALARMS_TYPE) != string::npos) ? VIBRATE_TYPE_SALARM : VIBRATE_TYPE_STANDARD;
602                 ntype = (path_.find(RINGTONES_TYPE) != string::npos) ? VIBRATE_TYPE_SRINGTONE : ntype;
603                 ntype = (path_.find(NOTIFICATIONS_TYPE) != string::npos) ? \
604                     VIBRATE_TYPE_SNOTIFICATION : ntype;
605                 vibrateData_->SetVibrateType(ntype);
606             } else {
607                 ntype = (path_.find(ALARMS_TYPE) != string::npos) ? VIBRATE_TYPE_GALARM : VIBRATE_TYPE_GENTLE;
608                 ntype = (path_.find(RINGTONES_TYPE) != string::npos) ? VIBRATE_TYPE_GRINGTONE : ntype;
609                 ntype = (path_.find(NOTIFICATIONS_TYPE) != string::npos) ? \
610                     VIBRATE_TYPE_GNOTIFICATION : ntype;
611                 vibrateData_->SetVibrateType(ntype);
612             }
613         }
614     }
615 
616     for (const auto &pair : g_vibratePlayModeMap) {
617         if (path_.find(pair.first) == 0) {
618             vibrateData_->SetPlayMode(pair.second.second);
619         }
620     }
621 
622     // file path
623     vibrateData_->SetData(path_);
624     auto dispName = RingtoneScannerUtils::GetFileNameFromUri(path_);
625     vibrateData_->SetDisplayName(dispName);
626     if (vibrateData_->GetTitle() == TITLE_DEFAULT) {
627         vibrateData_->SetTitle(RingtoneScannerUtils::GetFileTitle(vibrateData_->GetDisplayName()));
628     }
629 
630     // statinfo
631     vibrateData_->SetSize(statInfo.st_size);
632     vibrateData_->SetDateModified(static_cast<int64_t>(RingtoneFileUtils::Timespec2Millisecond(statInfo.st_mtim)));
633 
634     return E_OK;
635 }
636 
ScanFileInternal()637 int32_t RingtoneScannerObj::ScanFileInternal()
638 {
639     if (RingtoneScannerUtils::IsFileHidden(path_)) {
640         RINGTONE_ERR_LOG("the file is hidden");
641         return E_FILE_HIDDEN;
642     }
643 
644     bool flag = (path_.find(ROOT_VIBRATE_PRELOAD_PATH_NOAH_PATH) != std::string::npos) ? true : false;
645     flag |= (path_.find(ROOT_VIBRATE_PRELOAD_PATH_CHINA_PATH) != std::string::npos);
646     flag |= (path_.find(ROOT_VIBRATE_PRELOAD_PATH_OVERSEA_PATH) != std::string::npos);
647     std::string extension = RingtoneScannerUtils::GetFileExtension(path_);
648 
649     if (flag) {
650         if (extension.compare("json") == 0) {
651             isVibrateFile_ = true;
652             return ScanVibrateFile();
653         }
654         return E_INVALID_PATH;
655     }
656 
657     int32_t err = GetFileMetadata();
658     if (err != E_OK) {
659         if (err != E_SCANNED) {
660             RINGTONE_ERR_LOG("failed to get file metadata");
661         }
662         return err;
663     }
664     err = GetMediaInfo();
665     if (err != E_OK) {
666         RINGTONE_ERR_LOG("failed to get ringtone info");
667     }
668 
669     err = Commit();
670     if (err != E_OK) {
671         RINGTONE_ERR_LOG("failed to commit err %{public}d", err);
672         return err;
673     }
674 
675     return E_OK;
676 }
677 
ScanVibrateFile()678 int32_t RingtoneScannerObj::ScanVibrateFile()
679 {
680     int32_t err = GetFileMetadata();
681     if (err != E_OK) {
682         if (err != E_SCANNED) {
683             RINGTONE_ERR_LOG("failed to get vibrate file metadata");
684         }
685         isVibrateFile_ = false;
686         return err;
687     }
688 
689     if (type_ == FILE) {
690         err = Commit();
691         if (err != E_OK) {
692             RINGTONE_ERR_LOG("failed to commit err %{public}d", err);
693             isVibrateFile_ = false;
694             return err;
695         }
696     } else {
697         err = AddToTransaction();
698         if (err != E_OK) {
699             RINGTONE_ERR_LOG("failed to add to transaction err %{public}d", err);
700             isVibrateFile_ = false;
701             return err;
702         }
703     }
704 
705     isVibrateFile_ = false;
706     return E_OK;
707 }
708 
Commit()709 int32_t RingtoneScannerObj::Commit()
710 {
711     std::string tab = RINGTONE_TABLE;
712 
713     if (isVibrateFile_) {
714         tab = VIBRATE_TABLE;
715 
716         if (vibrateData_->GetVibrateId() != FILE_ID_DEFAULT) {
717             uri_ = RingtoneScannerDb::UpdateVibrateMetadata(*vibrateData_, tab);
718         } else {
719             uri_ = RingtoneScannerDb::InsertVibrateMetadata(*vibrateData_, tab);
720         }
721     } else {
722         if (data_->GetToneId() != FILE_ID_DEFAULT) {
723             uri_ = RingtoneScannerDb::UpdateMetadata(*data_, tab);
724         } else {
725             uri_ = RingtoneScannerDb::InsertMetadata(*data_, tab);
726         }
727     }
728 
729     return E_OK;
730 }
731 } // namespace Media
732 } // namespace OHOS
733