• 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 "MediaLibraryCloudUploadChecker"
17 
18 #include "cloud_upload_checker.h"
19 
20 #include <sys/stat.h>
21 
22 #include "media_file_utils.h"
23 #include "media_file_uri.h"
24 #include "medialibrary_unistore_manager.h"
25 #include "photo_album_column.h"
26 #include "thumbnail_const.h"
27 #include "media_column.h"
28 #include "preferences.h"
29 #include "preferences_helper.h"
30 #include "result_set_utils.h"
31 #include "thumbnail_const.h"
32 #include "medialibrary_object_utils.h"
33 #include "medialibrary_photo_operations.h"
34 #include "moving_photo_file_utils.h"
35 #include "medialibrary_subscriber.h"
36 
37 namespace OHOS {
38 namespace Media {
39 using namespace std;
40 using namespace NativeRdb;
41 
42 const std::int32_t BATCH_SIZE = 500;
43 const int32_t NO_ORIGIN_NO_LCD = 101;
44 
45 const int SCANLINE_DEFAULT_VERSION = 0;
46 const int SCANLINE_CURRENT_VERSION = 1;
47 
48 const std::string TASK_PROGRESS_XML = "/data/storage/el2/base/preferences/task_progress.xml";
49 const std::string NO_ORIGIN_PHOTO_NUMBER = "no_origin_photo_number";
50 const std::string NO_ORIGIN_BUT_LCD_PHOTO_NUMBER = "no_origin_but_lcd_photo_number";
51 const std::string SCANLINE_VERSION = "scanline_version";
52 
53 std::mutex CloudUploadChecker::mutex_;
54 
55 const std::string SQL_PHOTOS_TABLE_QUERY_NO_ORIGIN_BUT_LCD_COUNT = "SELECT"
56                                                                    " COUNT( * ) AS Count "
57                                                                    "FROM"
58                                                                    " Photos "
59                                                                    "WHERE"
60                                                                    " ( dirty = 100 OR dirty = 1 )"
61                                                                    " AND thumbnail_ready >= 3"
62                                                                    " AND lcd_visit_time >= 2"
63                                                                    " AND file_id > ?;";
64 
65 const std::string SQL_PHOTOS_TABLE_QUERY_NO_ORIGIN_BUT_LCD_PHOTO = "SELECT"
66                                                                    " file_id,"
67                                                                    " data,"
68                                                                    " size,"
69                                                                    " subtype,"
70                                                                    " moving_photo_effect_mode "
71                                                                    "FROM"
72                                                                    " Photos "
73                                                                    "WHERE"
74                                                                    " ( dirty = 100 OR dirty = 1 )"
75                                                                    " AND thumbnail_ready >= 3"
76                                                                    " AND lcd_visit_time >= 2"
77                                                                    " AND file_id > ?"
78                                                                    " LIMIT ?;";
79 
HandleNoOriginPhoto()80 void CloudUploadChecker::HandleNoOriginPhoto()
81 {
82     MEDIA_INFO_LOG("start handle no origin photo!");
83     int64_t startTime = MediaFileUtils::UTCTimeMilliSeconds();
84     int32_t errCode = E_OK;
85     shared_ptr<NativePreferences::Preferences> prefs =
86         NativePreferences::PreferencesHelper::GetPreferences(TASK_PROGRESS_XML, errCode);
87     CHECK_AND_RETURN_LOG(prefs, "get preferences error: %{public}d", errCode);
88     int32_t curFileId = prefs->GetInt(NO_ORIGIN_PHOTO_NUMBER, 0);
89     MEDIA_INFO_LOG("start file id: %{public}d", curFileId);
90     while (MedialibrarySubscriber::IsCurrentStatusOn() && QueryLcdPhotoCount(curFileId) > 0) {
91         MEDIA_INFO_LOG("handle origin photo curFileId: %{public}d", curFileId);
92         std::vector<CheckedPhotoInfo> photoInfos = QueryPhotoInfo(curFileId);
93         HandlePhotoInfos(photoInfos, curFileId);
94         prefs->PutInt(NO_ORIGIN_PHOTO_NUMBER, curFileId);
95         prefs->FlushSync();
96     }
97     MEDIA_INFO_LOG(
98         "end handle no origin photo! cost: %{public}" PRId64, MediaFileUtils::UTCTimeMilliSeconds() - startTime);
99     return;
100 }
101 
IsMovingPhoto(int32_t subtype,int32_t movingPhotoEffectMode)102 inline bool IsMovingPhoto(int32_t subtype, int32_t movingPhotoEffectMode)
103 {
104     return subtype == static_cast<int32_t>(PhotoSubType::MOVING_PHOTO) ||
105            movingPhotoEffectMode == static_cast<int32_t>(MovingPhotoEffectMode::IMAGE_ONLY);
106 }
107 
GetPhotoRealSize(const bool isMovingPhoto,const std::string & path,int64_t & size)108 int32_t GetPhotoRealSize(const bool isMovingPhoto, const std::string &path, int64_t &size)
109 {
110     if (isMovingPhoto) {
111         size = static_cast<int64_t>(MovingPhotoFileUtils::GetMovingPhotoSize(path));
112         return E_OK;
113     }
114     struct stat st {};
115     CHECK_AND_RETURN_RET_LOG(stat(path.c_str(), &st) == 0,
116         E_ERR,
117         "stat syscall failed, path=%{public}s, errno=%{public}d",
118         path.c_str(),
119         errno);
120 
121     size = static_cast<int64_t>(st.st_size);
122     return E_OK;
123 }
124 
UpdateFileSize(const CheckedPhotoInfo & photoInfo,bool isMovingPhoto)125 void CloudUploadChecker::UpdateFileSize(const CheckedPhotoInfo &photoInfo, bool isMovingPhoto)
126 {
127     int64_t size = 0;
128     CHECK_AND_RETURN_LOG(GetPhotoRealSize(isMovingPhoto, photoInfo.path, size) == E_OK,
129         "get photo real size failed, path=%{public}s",
130         photoInfo.path.c_str());
131 
132     CHECK_AND_RETURN_INFO_LOG(photoInfo.size != size,
133         "no need to update db file size, file_id=%{public}d, size=%{public}" PRId64,
134         photoInfo.fileId,
135         size);
136 
137     auto rdbStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
138     CHECK_AND_RETURN_LOG(rdbStore != nullptr, "rdbStore is nullptr");
139 
140     RdbPredicates predicates(PhotoColumn::PHOTOS_TABLE);
141     predicates.EqualTo(MediaColumn::MEDIA_ID, photoInfo.fileId);
142 
143     ValuesBucket values;
144     values.PutInt(PhotoColumn::PHOTO_DIRTY, static_cast<int32_t>(DirtyTypes::TYPE_NEW));
145     values.PutLong(MediaColumn::MEDIA_SIZE, size);
146 
147     int32_t updateCount = 0;
148     int32_t err = rdbStore->Update(updateCount, values, predicates);
149 
150     CHECK_AND_RETURN_LOG(err == NativeRdb::E_OK,
151         "update db file size failed, file_id=%{public}d, err=%{public}d",
152         photoInfo.fileId,
153         err);
154 
155     MEDIA_INFO_LOG("update db file size succeed, file_id=%{public}d, old size=%{public}" PRId64
156                    ", new size=%{public}" PRId64,
157         photoInfo.fileId,
158         photoInfo.size,
159         size);
160 }
161 
HandleMissingFile(const CheckedPhotoInfo & photoInfo,bool isMovingPhoto,std::vector<std::string> & noLcdList)162 void CloudUploadChecker::HandleMissingFile(
163     const CheckedPhotoInfo &photoInfo, bool isMovingPhoto, std::vector<std::string> &noLcdList)
164 {
165     std::string lcdPath = GetThumbnailPath(photoInfo.path, THUMBNAIL_LCD_SUFFIX);
166     if (!MediaFileUtils::IsFileExists(lcdPath)) {
167         MEDIA_WARN_LOG("lcd path does not exist, file_id: %{public}d", photoInfo.fileId);
168         noLcdList.push_back(std::to_string(photoInfo.fileId));
169         return;
170     }
171 
172     CHECK_AND_RETURN_LOG(MediaFileUtils::CopyFileUtil(lcdPath, photoInfo.path),
173         "copy lcd to origin photo failed, file_id: %{public}d",
174         photoInfo.fileId);
175 
176     MEDIA_INFO_LOG("copy lcd to origin photo succeed, file_id: %{public}d", photoInfo.fileId);
177     UpdateFileSize(photoInfo, isMovingPhoto);
178 }
179 
HandlePhotoInfos(const std::vector<CheckedPhotoInfo> & photoInfos,int32_t & curFileId)180 void CloudUploadChecker::HandlePhotoInfos(const std::vector<CheckedPhotoInfo> &photoInfos, int32_t &curFileId)
181 {
182     std::vector<std::string> noLcdList;
183 
184     for (const CheckedPhotoInfo &photoInfo : photoInfos) {
185         CHECK_AND_BREAK_INFO_LOG(MedialibrarySubscriber::IsCurrentStatusOn(), "current status is off, break");
186         curFileId = photoInfo.fileId;
187         bool isMovingPhoto = IsMovingPhoto(photoInfo.subtype, photoInfo.movingPhotoEffectMode);
188         if (MediaFileUtils::IsFileExists(photoInfo.path)) {
189             UpdateFileSize(photoInfo, isMovingPhoto);
190             continue;
191         }
192         HandleMissingFile(photoInfo, isMovingPhoto, noLcdList);
193     }
194     UpdateDirty(noLcdList, NO_ORIGIN_NO_LCD);
195 }
196 
UpdateDirty(const std::vector<std::string> & idList,int32_t dirtyType)197 void CloudUploadChecker::UpdateDirty(const std::vector<std::string> &idList, int32_t dirtyType)
198 {
199     CHECK_AND_RETURN_INFO_LOG(!idList.empty(), "idList is empty");
200     auto rdbStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
201     CHECK_AND_RETURN_LOG(rdbStore != nullptr, "Failed to get rdbstore!");
202     RdbPredicates predicates(PhotoColumn::PHOTOS_TABLE);
203     predicates.In(MediaColumn::MEDIA_ID, idList);
204     ValuesBucket values;
205     values.PutInt(PhotoColumn::PHOTO_DIRTY, dirtyType);
206     int32_t updateCount = 0;
207     int32_t err = rdbStore->Update(updateCount, values, predicates);
208     MEDIA_INFO_LOG("dirty: %{public}d, idList size: %{public}zu, update size: %{public}d, err: %{public}d",
209         dirtyType,
210         idList.size(),
211         updateCount,
212         err);
213 }
214 
QueryPhotoInfo(int32_t startFileId)215 std::vector<CheckedPhotoInfo> CloudUploadChecker::QueryPhotoInfo(int32_t startFileId)
216 {
217     std::vector<CheckedPhotoInfo> photoInfos;
218     auto rdbStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
219     CHECK_AND_RETURN_RET_LOG(rdbStore != nullptr, photoInfos, "Failed to get rdbstore!");
220 
221     const std::vector<NativeRdb::ValueObject> bindArgs = {startFileId, BATCH_SIZE};
222     auto resultSet = rdbStore->QuerySql(SQL_PHOTOS_TABLE_QUERY_NO_ORIGIN_BUT_LCD_PHOTO, bindArgs);
223     bool cond = resultSet != nullptr && resultSet->GoToFirstRow() == NativeRdb::E_OK;
224     CHECK_AND_RETURN_RET_LOG(cond, photoInfos, "resultSet is null or count is 0");
225 
226     do {
227         std::string path =
228             get<std::string>(ResultSetUtils::GetValFromColumn(MediaColumn::MEDIA_FILE_PATH, resultSet, TYPE_STRING));
229         CHECK_AND_CONTINUE_ERR_LOG(!path.empty(), "Failed to get data path");
230         CheckedPhotoInfo photoInfo;
231         photoInfo.fileId = get<int32_t>(ResultSetUtils::GetValFromColumn(MediaColumn::MEDIA_ID, resultSet, TYPE_INT32));
232         photoInfo.path = path;
233         photoInfo.size = get<int64_t>(ResultSetUtils::GetValFromColumn(MediaColumn::MEDIA_SIZE, resultSet, TYPE_INT64));
234         photoInfo.subtype =
235             get<int32_t>(ResultSetUtils::GetValFromColumn(PhotoColumn::PHOTO_SUBTYPE, resultSet, TYPE_INT32));
236         photoInfo.movingPhotoEffectMode = get<int32_t>(
237             ResultSetUtils::GetValFromColumn(PhotoColumn::MOVING_PHOTO_EFFECT_MODE, resultSet, TYPE_INT32));
238         photoInfos.push_back(photoInfo);
239     } while (MedialibrarySubscriber::IsCurrentStatusOn() && resultSet->GoToNextRow() == NativeRdb::E_OK);
240     return photoInfos;
241 }
242 
QueryLcdPhotoCount(int32_t startFileId)243 int32_t CloudUploadChecker::QueryLcdPhotoCount(int32_t startFileId)
244 {
245     auto rdbStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
246     CHECK_AND_RETURN_RET_LOG(rdbStore != nullptr, E_HAS_DB_ERROR, "Failed to get rdbStore.");
247     const std::vector<NativeRdb::ValueObject> bindArgs = {startFileId};
248     auto resultSet = rdbStore->QuerySql(SQL_PHOTOS_TABLE_QUERY_NO_ORIGIN_BUT_LCD_COUNT, bindArgs);
249     CHECK_AND_RETURN_RET_LOG(
250         resultSet != nullptr && resultSet->GoToFirstRow() == NativeRdb::E_OK, 0, "resultSet is null or count is 0");
251     return get<int32_t>(ResultSetUtils::GetValFromColumn("Count", resultSet, TYPE_INT32));
252 }
253 
RepairNoOriginPhoto()254 void CloudUploadChecker::RepairNoOriginPhoto()
255 {
256     std::unique_lock<std::mutex> lock(mutex_, std::defer_lock);
257     CHECK_AND_RETURN_WARN_LOG(lock.try_lock(), "Repairing no origin photos has started, skipping this operation");
258     MEDIA_INFO_LOG("start repair no origin photo!");
259     int32_t errCode = E_OK;
260     shared_ptr<NativePreferences::Preferences> prefs =
261         NativePreferences::PreferencesHelper::GetPreferences(TASK_PROGRESS_XML, errCode);
262     CHECK_AND_RETURN_LOG(prefs, "get preferences error: %{public}d", errCode);
263     int scanlineVersion = prefs->GetInt(SCANLINE_VERSION, SCANLINE_DEFAULT_VERSION);
264     MEDIA_INFO_LOG("scanline version: %{public}d", scanlineVersion);
265     if (scanlineVersion < SCANLINE_CURRENT_VERSION) {
266         prefs->PutInt(NO_ORIGIN_PHOTO_NUMBER, 0);
267         prefs->PutInt(SCANLINE_VERSION, SCANLINE_CURRENT_VERSION);
268         prefs->FlushSync();
269     }
270     HandleNoOriginPhoto();
271     MEDIA_INFO_LOG("end repair no origin photo!");
272 }
273 }  // namespace Media
274 }  // namespace OHOS