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