• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 }