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 "MediaLibraryAllAlbumRefreshProcessor"
17
18 #include "medialibrary_all_album_refresh_processor.h"
19
20 #include "albums_refresh_manager.h"
21 #include "cloud_sync_helper.h"
22 #include "ffrt.h"
23 #include "ffrt_inner.h"
24 #include "media_log.h"
25 #include "medialibrary_errno.h"
26 #include "medialibrary_rdb_utils.h"
27 #include "medialibrary_unistore_manager.h"
28 #include "photo_album_column.h"
29 #include "vision_album_column.h"
30 #include "vision_column.h"
31
32 namespace OHOS {
33 namespace Media {
34 using namespace std;
35 namespace {
36 const int64_t REFRESH_ALL_ALBUMS_INTERVAL = 86400000000; // 24 hours
37 }
38
39 shared_ptr<MediaLibraryAllAlbumRefreshProcessor> MediaLibraryAllAlbumRefreshProcessor::instance_ = nullptr;
40 mutex MediaLibraryAllAlbumRefreshProcessor::instanceMutex_;
41
GetInstance()42 shared_ptr<MediaLibraryAllAlbumRefreshProcessor> MediaLibraryAllAlbumRefreshProcessor::GetInstance()
43 {
44 if (instance_ == nullptr) {
45 lock_guard<mutex> guard(instanceMutex_);
46 if (instance_ != nullptr) {
47 return instance_;
48 }
49 auto *mediaLibraryAllAlbumRefreshProcessor = new (nothrow)MediaLibraryAllAlbumRefreshProcessor();
50 if (mediaLibraryAllAlbumRefreshProcessor == nullptr) {
51 MEDIA_ERR_LOG("Failed to new MediaLibraryAllAlbumRefreshProcessor");
52 }
53 instance_ = shared_ptr<MediaLibraryAllAlbumRefreshProcessor>(mediaLibraryAllAlbumRefreshProcessor);
54 }
55 return instance_;
56 }
57
MediaLibraryAllAlbumRefreshProcessor()58 MediaLibraryAllAlbumRefreshProcessor::MediaLibraryAllAlbumRefreshProcessor()
59 {
60 }
61
GetNowTimeUs()62 int64_t MediaLibraryAllAlbumRefreshProcessor::GetNowTimeUs()
63 {
64 struct timespec t;
65 constexpr int64_t SEC_TO_USEC = 1e6;
66 constexpr int64_t NSEC_TO_USEC = 1e3;
67 clock_gettime(CLOCK_REALTIME, &t);
68 return t.tv_sec * SEC_TO_USEC + t.tv_nsec / NSEC_TO_USEC;
69 }
70
OnCurrentStatusChanged(bool currentStatus)71 void MediaLibraryAllAlbumRefreshProcessor::OnCurrentStatusChanged(bool currentStatus)
72 {
73 std::lock_guard<std::mutex> lock(refreshAllAlbumsLock_);
74 currentStatus_ = currentStatus;
75 MEDIA_INFO_LOG("OnCurrentStatusChanged! %{public}d", currentStatus_);
76 if (currentStatus_) {
77 PostRefreshAllAlbumsTask();
78 }
79 }
80
OnCloudSyncStateChanged(bool isCloudSyncing)81 void MediaLibraryAllAlbumRefreshProcessor::OnCloudSyncStateChanged(bool isCloudSyncing)
82 {
83 std::lock_guard<std::mutex> lock(refreshAllAlbumsLock_);
84 isCloudSyncing_ = isCloudSyncing;
85 MEDIA_INFO_LOG("OnCloudSyncStateChanged! %{public}d", isCloudSyncing_);
86 if (!isCloudSyncing_) {
87 PostRefreshAllAlbumsTask();
88 }
89 }
90
CheckRefreshConditionLocked()91 bool MediaLibraryAllAlbumRefreshProcessor::CheckRefreshConditionLocked()
92 {
93 return currentStatus_ && !isCloudSyncing_ &&
94 (albumRefreshStatus_ != AlbumRefreshStatus::NOT_START || lastRefreshAllAlbumsTime_ == 0 ||
95 GetNowTimeUs() - lastRefreshAllAlbumsTime_ > REFRESH_ALL_ALBUMS_INTERVAL);
96 }
97
GetNextRefreshStatus(AlbumRefreshStatus albumRefreshStatus)98 AlbumRefreshStatus GetNextRefreshStatus(AlbumRefreshStatus albumRefreshStatus)
99 {
100 switch (albumRefreshStatus) {
101 case AlbumRefreshStatus::NOT_START:
102 return AlbumRefreshStatus::SYSTEM;
103 case AlbumRefreshStatus::SYSTEM:
104 return AlbumRefreshStatus::USER;
105 case AlbumRefreshStatus::USER:
106 return AlbumRefreshStatus::SOURCE;
107 case AlbumRefreshStatus::SOURCE:
108 return AlbumRefreshStatus::ANALYSIS;
109 case AlbumRefreshStatus::ANALYSIS:
110 return AlbumRefreshStatus::NOT_START;
111 default:
112 return AlbumRefreshStatus::NOT_START;
113 }
114 }
115
GetAlbumId(const shared_ptr<NativeRdb::ResultSet> & resultSet)116 static int32_t GetAlbumId(const shared_ptr<NativeRdb::ResultSet>& resultSet)
117 {
118 int32_t albumId = 0;
119 CHECK_AND_RETURN_RET_LOG(resultSet->GetInt(0, albumId) == NativeRdb::E_OK,
120 E_HAS_DB_ERROR, "Failed to get album_id");
121 return albumId;
122 }
123
GetPhotoAlbumIds(PhotoAlbumSubType albumSubtype,int32_t currentAlbumId,vector<int32_t> & albumIds)124 int32_t GetPhotoAlbumIds(PhotoAlbumSubType albumSubtype, int32_t currentAlbumId, vector<int32_t>& albumIds)
125 {
126 auto rdbStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
127 CHECK_AND_RETURN_RET_LOG(rdbStore != nullptr, E_HAS_DB_ERROR, "rdbStore is null");
128
129 NativeRdb::RdbPredicates predicates(PhotoAlbumColumns::TABLE);
130 predicates.EqualTo(PhotoAlbumColumns::ALBUM_SUBTYPE, to_string(albumSubtype))
131 ->And()
132 ->GreaterThan(PhotoAlbumColumns::ALBUM_ID, currentAlbumId)
133 ->OrderByAsc(PhotoAlbumColumns::ALBUM_ID);
134 vector<string> columns = { PhotoAlbumColumns::ALBUM_ID };
135 shared_ptr<NativeRdb::ResultSet> resultSet = rdbStore->Query(predicates, columns);
136 CHECK_AND_RETURN_RET_LOG(resultSet != nullptr, E_HAS_DB_ERROR, "Failed to query photo album");
137
138 while (resultSet->GoToNextRow() == E_OK) {
139 int32_t albumId = GetAlbumId(resultSet);
140 if (albumId <= 0) {
141 MEDIA_WARN_LOG("Failed to GetAlbumId: %{public}d", albumId);
142 continue;
143 }
144 albumIds.push_back(albumId);
145 }
146 return E_OK;
147 }
148
GetAnalysisAlbumIds(int32_t currentAlbumId,vector<int32_t> & albumIds)149 int32_t GetAnalysisAlbumIds(int32_t currentAlbumId, vector<int32_t>& albumIds)
150 {
151 auto rdbStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
152 CHECK_AND_RETURN_RET_LOG(rdbStore != nullptr, E_HAS_DB_ERROR, "rdbStore is null");
153
154 NativeRdb::RdbPredicates predicates(ANALYSIS_ALBUM_TABLE);
155 predicates.GreaterThan(ALBUM_ID, currentAlbumId)->OrderByAsc(ALBUM_ID);
156 vector<string> columns = { ALBUM_ID };
157 shared_ptr<NativeRdb::ResultSet> resultSet = rdbStore->Query(predicates, columns);
158 CHECK_AND_RETURN_RET_LOG(resultSet != nullptr, E_HAS_DB_ERROR, "Failed to query analysis album");
159
160 while (resultSet->GoToNextRow() == E_OK) {
161 int32_t albumId = GetAlbumId(resultSet);
162 if (albumId <= 0) {
163 MEDIA_WARN_LOG("Failed to GetAlbumId: %{public}d", albumId);
164 continue;
165 }
166 albumIds.push_back(albumId);
167 }
168 return E_OK;
169 }
170
GetAlbumIds(AlbumRefreshStatus albumRefreshStatus,int32_t currentAlbumId,vector<int32_t> & albumIds)171 int32_t GetAlbumIds(AlbumRefreshStatus albumRefreshStatus, int32_t currentAlbumId, vector<int32_t>& albumIds)
172 {
173 switch (albumRefreshStatus) {
174 case AlbumRefreshStatus::SYSTEM:
175 // refresh all albums for system album, no need to fill albumIds
176 return E_OK;
177 case AlbumRefreshStatus::USER:
178 return GetPhotoAlbumIds(PhotoAlbumSubType::USER_GENERIC, currentAlbumId, albumIds);
179 case AlbumRefreshStatus::SOURCE:
180 return GetPhotoAlbumIds(PhotoAlbumSubType::SOURCE_GENERIC, currentAlbumId, albumIds);
181 case AlbumRefreshStatus::ANALYSIS:
182 return GetAnalysisAlbumIds(currentAlbumId, albumIds);
183 default:
184 MEDIA_ERR_LOG("Failed to check album refresh status: %{public}d", static_cast<int32_t>(albumRefreshStatus));
185 return E_ERR;
186 }
187 }
188
RefreshAlbums(AlbumRefreshStatus albumRefreshStatus,const vector<int32_t> & albumIds)189 int32_t MediaLibraryAllAlbumRefreshProcessor::RefreshAlbums(AlbumRefreshStatus albumRefreshStatus,
190 const vector<int32_t>& albumIds)
191 {
192 auto rdbStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
193 CHECK_AND_RETURN_RET_LOG(rdbStore != nullptr, E_HAS_DB_ERROR, "rdbStore is null");
194 if (albumRefreshStatus == AlbumRefreshStatus::SYSTEM) {
195 MediaLibraryRdbUtils::UpdateSystemAlbumsByUris(rdbStore, AlbumOperationType::DEFAULT);
196 return E_OK;
197 }
198
199 int32_t currentAlbumId = currentAlbumId_;
200 for (auto iter = albumIds.begin(); iter != albumIds.end(); iter++) {
201 int32_t albumId = *iter;
202 if (albumRefreshStatus == AlbumRefreshStatus::USER) {
203 MediaLibraryRdbUtils::UpdateUserAlbumInternal(rdbStore, { to_string(albumId) }, false, false);
204 MediaLibraryRdbUtils::UpdateUserAlbumHiddenState(rdbStore, { to_string(albumId) });
205 } else if (albumRefreshStatus == AlbumRefreshStatus::SOURCE) {
206 MediaLibraryRdbUtils::UpdateSourceAlbumInternal(rdbStore, { to_string(albumId) }, false, false);
207 MediaLibraryRdbUtils::UpdateSourceAlbumHiddenState(rdbStore, { to_string(albumId) });
208 } else if (albumRefreshStatus == AlbumRefreshStatus::ANALYSIS) {
209 MediaLibraryRdbUtils::UpdateAnalysisAlbumInternal(rdbStore, { to_string(albumId) });
210 } else {
211 MEDIA_WARN_LOG("Ignore to refresh album %{public}d id: %{public}d",
212 static_cast<int32_t>(albumRefreshStatus), albumId);
213 }
214
215 currentAlbumId = albumId;
216 if (!currentStatus_ || isCloudSyncing_) {
217 MEDIA_INFO_LOG("Condition changes, currentStatus_: %{public}d, isCloudSyncing_: %{public}d",
218 currentStatus_, isCloudSyncing_);
219 break;
220 }
221 }
222
223 if (albumIds.empty() || currentAlbumId == albumIds.back()) {
224 MEDIA_INFO_LOG("Finish refreshing album type: %{public}d", albumRefreshStatus);
225 return E_OK;
226 }
227 MEDIA_INFO_LOG(
228 "Refresh album type: %{public}d, album id: %{public}d, currentStatus_: %{public}d, isCloudSyncing_: %{public}d",
229 albumRefreshStatus, currentAlbumId, currentStatus_, isCloudSyncing_);
230 return currentAlbumId;
231 }
232
TryRefreshAllAlbums()233 void MediaLibraryAllAlbumRefreshProcessor::TryRefreshAllAlbums()
234 {
235 {
236 std::lock_guard<std::mutex> lock(refreshAllAlbumsLock_);
237 if (!CheckRefreshConditionLocked()) {
238 MEDIA_DEBUG_LOG("Not meet the condition of refreshing albums");
239 return;
240 }
241 MEDIA_INFO_LOG("RefreshAllAlbums! now: %{public}" PRId64 ", last : %{public}" PRId64,
242 GetNowTimeUs(), lastRefreshAllAlbumsTime_);
243 lastRefreshAllAlbumsTime_ = GetNowTimeUs();
244 }
245
246 if (albumRefreshStatus_ == AlbumRefreshStatus::NOT_START) {
247 albumRefreshStatus_ = GetNextRefreshStatus(AlbumRefreshStatus::NOT_START);
248 }
249
250 while (albumRefreshStatus_ != AlbumRefreshStatus::NOT_START && currentStatus_ && !isCloudSyncing_) {
251 vector<int32_t> albumIds = {};
252 int32_t ret = GetAlbumIds(albumRefreshStatus_, currentAlbumId_, albumIds);
253 if (ret < E_OK) {
254 albumRefreshStatus_ = GetNextRefreshStatus(albumRefreshStatus_);
255 currentAlbumId_ = 0;
256 continue;
257 }
258
259 ret = RefreshAlbums(albumRefreshStatus_, albumIds);
260 if (ret > 0) {
261 currentAlbumId_ = ret;
262 break;
263 }
264 albumRefreshStatus_ = GetNextRefreshStatus(albumRefreshStatus_);
265 currentAlbumId_ = 0;
266 }
267 }
268
PostRefreshAllAlbumsTask()269 void MediaLibraryAllAlbumRefreshProcessor::PostRefreshAllAlbumsTask()
270 {
271 ffrt::submit([this]() { TryRefreshAllAlbums(); });
272 }
273 } // namespace Media
274 } // namespace OHOS
275