1 /*
2 * Copyright (C) 2025 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 #define MLOG_TAG "ForeGroundAnalysisMeta"
16 #include "foreground_analysis_meta.h"
17
18 #include "media_analysis_helper.h"
19 #include "media_column.h"
20 #include "media_file_utils.h"
21 #include "media_log.h"
22 #include "medialibrary_db_const.h"
23 #include "medialibrary_errno.h"
24 #include "medialibrary_unistore_manager.h"
25 #include "rdb_utils.h"
26 #include "search_column.h"
27 #include "user_photography_info_column.h"
28 #include "vision_column.h"
29 #include "vision_total_column.h"
30
31 using namespace OHOS::NativeRdb;
32 using Uri = OHOS::Uri;
33 using namespace OHOS::DataShare;
34
35 namespace OHOS {
36 namespace Media {
37 const int FRONT_CV_MAX_LIMIT = 20;
38 const int FRONT_INDEX_MAX_LIMIT = 5000;
ForegroundAnalysisMeta(std::shared_ptr<NativeRdb::ResultSet> result)39 ForegroundAnalysisMeta::ForegroundAnalysisMeta(std::shared_ptr<NativeRdb::ResultSet> result)
40 {
41 if (result == nullptr) {
42 return;
43 }
44 while (result->GoToNextRow() == NativeRdb::E_OK) {
45 int colIndex = 0;
46 result->GetColumnIndex(FRONT_INDEX_LIMIT, colIndex);
47 result->GetInt(colIndex, frontIndexLimit_);
48 if (frontIndexLimit_ == 0) {
49 frontIndexLimit_ = FRONT_INDEX_MAX_LIMIT;
50 }
51 result->GetColumnIndex(FRONT_INDEX_MODIFIED, colIndex);
52 result->GetLong(colIndex, frontIndexModified_);
53 result->GetColumnIndex(FRONT_INDEX_COUNT, colIndex);
54 result->GetInt(colIndex, frontIndexCount_);
55 result->GetColumnIndex(FRONT_CV_MODIFIED, colIndex);
56 result->GetLong(colIndex, frontCvModified_);
57 result->GetColumnIndex(FRONT_CV_COUNT, colIndex);
58 result->GetInt(colIndex, frontCvCount_);
59 isInit_ = true;
60 }
61 }
62
~ForegroundAnalysisMeta()63 ForegroundAnalysisMeta::~ForegroundAnalysisMeta() {}
64
GenerateOpType(MediaLibraryCommand & cmd)65 int32_t ForegroundAnalysisMeta::GenerateOpType(MediaLibraryCommand &cmd)
66 {
67 int errCode = E_OK;
68 if (IsMetaDirtyed()) {
69 errCode = RefreshMeta();
70 if (errCode != E_OK) {
71 MEDIA_ERR_LOG("refresh err:%{public}d", errCode);
72 return errCode;
73 }
74 }
75 errCode = CheckCvAnalysisCondition(cmd);
76 if (errCode != E_OK) {
77 MEDIA_ERR_LOG("chk cv err:%{public}d", errCode);
78 return errCode;
79 }
80 errCode = CheckIndexAnalysisCondition(cmd);
81 if (errCode != E_OK) {
82 MEDIA_ERR_LOG("chk index err:%{public}d", errCode);
83 return errCode;
84 }
85 taskId_ = GetCurTaskId(cmd);
86 return E_OK;
87 }
88
IsMetaDirtyed()89 bool ForegroundAnalysisMeta::IsMetaDirtyed()
90 {
91 std::time_t cvTime = frontCvModified_ / 1000;
92 std::time_t indexTime = frontIndexModified_ / 1000;
93 std::time_t curTime = MediaFileUtils::UTCTimeMilliSeconds() / 1000;
94 std::tm cvTm;
95 localtime_r(&cvTime, &cvTm);
96 std::tm indexTm;
97 localtime_r(&indexTime, &indexTm);
98 std::tm curTm;
99 localtime_r(&curTime, &curTm);
100 return (cvTm.tm_year != curTm.tm_year) || (cvTm.tm_mon != curTm.tm_mon) || (cvTm.tm_mday != curTm.tm_mday) ||
101 (indexTm.tm_year != curTm.tm_year) || (indexTm.tm_mon != curTm.tm_mon) || (indexTm.tm_mday != curTm.tm_mday) ||
102 !isInit_;
103 }
104
RefreshMeta()105 int32_t ForegroundAnalysisMeta::RefreshMeta()
106 {
107 auto rdbStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
108 if (rdbStore == nullptr) {
109 return E_ERR;
110 }
111 int64_t curMoified = MediaFileUtils::UTCTimeMilliSeconds();
112 frontIndexModified_ = curMoified;
113 frontCvModified_ = curMoified;
114 frontIndexCount_ = 0;
115 frontCvCount_ = 0;
116 ValuesBucket valuesBucket;
117 valuesBucket.Put(FRONT_CV_MODIFIED, frontCvModified_);
118 valuesBucket.Put(FRONT_CV_COUNT, frontCvCount_);
119 valuesBucket.Put(FRONT_INDEX_MODIFIED, frontIndexModified_);
120 valuesBucket.Put(FRONT_INDEX_COUNT, frontIndexCount_);
121 MEDIA_INFO_LOG("refresh cv meta, insert:%{public}d", !isInit_);
122 if (!isInit_) {
123 int64_t outRowId = 0;
124 int errCode = rdbStore->Insert(outRowId, USER_PHOTOGRAPHY_INFO_TABLE, valuesBucket);
125 if (errCode == E_OK) {
126 isInit_ = true;
127 }
128 return errCode;
129 }
130 int changedRows = 0;
131 RdbPredicates predicates(USER_PHOTOGRAPHY_INFO_TABLE);
132 return rdbStore->Update(changedRows, valuesBucket, predicates);
133 }
134
CheckCvAnalysisCondition(MediaLibraryCommand & cmd)135 int32_t ForegroundAnalysisMeta::CheckCvAnalysisCondition(MediaLibraryCommand &cmd)
136 {
137 if (frontCvCount_ >= FRONT_CV_MAX_LIMIT) {
138 return E_OK;
139 }
140 std::vector<std::string> fileIds;
141 int32_t errCode = QueryPendingAnalyzeFileIds(cmd, fileIds);
142 if (errCode != E_OK) {
143 return errCode;
144 }
145 if (!fileIds.empty()) {
146 fileIds_ = std::move(fileIds);
147 opType_ |= ForegroundAnalysisOpType::OCR_AND_LABEL;
148 if (frontIndexCount_ < frontIndexLimit_) {
149 opType_ |= ForegroundAnalysisOpType::SEARCH_INDEX;
150 }
151 }
152 return E_OK;
153 }
154
CheckIndexAnalysisCondition(MediaLibraryCommand & cmd)155 int32_t ForegroundAnalysisMeta::CheckIndexAnalysisCondition(MediaLibraryCommand &cmd)
156 {
157 if ((frontIndexCount_ >= frontIndexLimit_) || (opType_ & ForegroundAnalysisOpType::SEARCH_INDEX)) {
158 return E_OK;
159 }
160 int32_t pengdIndexCount = 0;
161 int32_t errCode = QueryPendingIndexCount(cmd, pengdIndexCount);
162 if (errCode != E_OK) {
163 return errCode;
164 }
165 if (pengdIndexCount > 0) {
166 opType_ |= ForegroundAnalysisOpType::SEARCH_INDEX;
167 }
168 return E_OK;
169 }
170
StartAnalysisService()171 void ForegroundAnalysisMeta::StartAnalysisService()
172 {
173 if (opType_ == ForegroundAnalysisOpType::FOREGROUND_NOT_HANDLE) {
174 return;
175 }
176 MEDIA_INFO_LOG("prepare submit taskId:%{public}d, opType:%{public}d, size:%{public}zu", taskId_, opType_,
177 fileIds_.size());
178 }
179
QueryPendingAnalyzeFileIds(MediaLibraryCommand & cmd,std::vector<std::string> & fileIds)180 int32_t ForegroundAnalysisMeta::QueryPendingAnalyzeFileIds(MediaLibraryCommand &cmd, std::vector<std::string> &fileIds)
181 {
182 auto rdbStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
183 if (rdbStore == nullptr) {
184 MEDIA_ERR_LOG("db is null");
185 return E_ERR;
186 }
187 std::string onClause = VISION_TOTAL_TABLE + "." + MediaColumn::MEDIA_ID + " = " + PhotoColumn::PHOTOS_TABLE + "." +
188 MediaColumn::MEDIA_ID;
189 std::string colmun = VISION_TOTAL_TABLE + "." + MediaColumn::MEDIA_ID;
190 std::string whereClause = cmd.GetAbsRdbPredicates()->GetWhereClause();
191 ValueObject valueObject;
192 int32_t analysisType = AnalysisType::ANALYSIS_SEARCH_INDEX;
193 if (cmd.GetValueBucket().GetObject(FOREGROUND_ANALYSIS_TYPE, valueObject)) {
194 valueObject.GetInt(analysisType);
195 }
196 AppendAnalysisTypeOnWhereClause(analysisType, whereClause);
197 std::string orderBy = " ORDER BY " + PhotoColumn::PHOTOS_TABLE + "." + MediaColumn::MEDIA_DATE_MODIFIED;
198 std::string limit = " LIMIT " + std::to_string(std::max(0, FRONT_CV_MAX_LIMIT - frontCvCount_));
199 std::string sql = "SELECT " + colmun + " FROM " + VISION_TOTAL_TABLE + " INNER JOIN " + PhotoColumn::PHOTOS_TABLE +
200 " ON " + onClause + " WHERE " + whereClause + orderBy + limit;
201 auto result = rdbStore->QuerySql(sql, cmd.GetAbsRdbPredicates()->GetWhereArgs());
202 if (result == nullptr) {
203 MEDIA_ERR_LOG("query err");
204 return E_ERR;
205 }
206 while (result->GoToNextRow() == NativeRdb::E_OK) {
207 int fileId;
208 int colIndex = 0;
209 result->GetColumnIndex(MediaColumn::MEDIA_ID, colIndex);
210 result->GetInt(colIndex, fileId);
211 fileIds.push_back(std::to_string(fileId));
212 }
213 result->Close();
214 if (fileIds.empty()) {
215 MEDIA_INFO_LOG("no fileId match");
216 } else {
217 MEDIA_INFO_LOG("cv match cnt:%{public}zu", fileIds.size());
218 }
219 return E_OK;
220 }
221
AppendAnalysisTypeOnWhereClause(int32_t type,std::string & whereClause)222 void ForegroundAnalysisMeta::AppendAnalysisTypeOnWhereClause(int32_t type, std::string &whereClause)
223 {
224 if (!whereClause.empty()) {
225 whereClause.append(" AND ");
226 }
227 static const std::map<int32_t, std::string> FRONT_ANALYSIS_WHERE_CLAUSE_MAP = {
228 { ANALYSIS_SEARCH_INDEX, VISION_TOTAL_TABLE + "." + STATUS + " = 0" + " AND (" + VISION_TOTAL_TABLE + "." +
229 OCR + " = 0 OR " + VISION_TOTAL_TABLE + "." + LABEL + " = 0)" },
230 };
231 std::string analysisTypeClause;
232 auto it = FRONT_ANALYSIS_WHERE_CLAUSE_MAP.find(type);
233 if (it != FRONT_ANALYSIS_WHERE_CLAUSE_MAP.end()) {
234 analysisTypeClause = it->second;
235 }
236 if (analysisTypeClause.empty()) {
237 whereClause.append(" 1 = 1 ");
238 } else {
239 whereClause.append(" (" + analysisTypeClause + ") ");
240 }
241 }
242
QueryPendingIndexCount(MediaLibraryCommand & cmd,int32_t & count)243 int32_t ForegroundAnalysisMeta::QueryPendingIndexCount(MediaLibraryCommand &cmd, int32_t &count)
244 {
245 auto rdbStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
246 if (rdbStore == nullptr) {
247 return E_ERR;
248 }
249 std::string onClause = SEARCH_TOTAL_TABLE + "." + MediaColumn::MEDIA_ID + " = " + PhotoColumn::PHOTOS_TABLE + "." +
250 MediaColumn::MEDIA_ID;
251 std::string colmun = "COUNT(1)";
252 std::string whereClause = SEARCH_TOTAL_TABLE + "." + TBL_SEARCH_PHOTO_STATUS + " in (0, 2)";
253 std::string sql = "SELECT " + colmun + " FROM " + SEARCH_TOTAL_TABLE + " INNER JOIN " + PhotoColumn::PHOTOS_TABLE +
254 " ON " + onClause + " WHERE " + whereClause;
255 auto result = rdbStore->QuerySql(sql);
256 if (result == nullptr) {
257 MEDIA_ERR_LOG("query err");
258 return E_ERR;
259 }
260 while (result->GoToNextRow() == NativeRdb::E_OK) {
261 int colIndex = 0;
262 result->GetInt(colIndex, count);
263 }
264 MEDIA_INFO_LOG("index match cnt:%{public}d", count);
265 result->Close();
266 return E_OK;
267 }
268
GetCurTaskId(MediaLibraryCommand & cmd)269 int32_t ForegroundAnalysisMeta::GetCurTaskId(MediaLibraryCommand &cmd)
270 {
271 int32_t curTaskId = -1;
272 ValueObject valueObject;
273 if (cmd.GetValueBucket().GetObject(FOREGROUND_ANALYSIS_TASK_ID, valueObject)) {
274 valueObject.GetInt(curTaskId);
275 }
276 return curTaskId;
277 }
278 }
279 }