• 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 #include "media_asset_rdbstore.h"
17 
18 #include <unordered_set>
19 
20 #include "media_file_uri.h"
21 #include "media_file_utils.h"
22 #include "media_log.h"
23 #include "medialibrary_tracer.h"
24 #include "parameter.h"
25 #include "parameters.h"
26 #include "photo_album_column.h"
27 #include "photo_map_column.h"
28 #include "vision_column.h"
29 
30 using namespace std;
31 using namespace OHOS::NativeRdb;
32 using namespace OHOS::RdbDataShareAdapter;
33 using namespace OHOS::Media::MediaOperation;
34 
35 namespace OHOS {
36 namespace Media {
37 
38 const std::string MEDIA_LIBRARY_STARTUP_PARAM_PREFIX = "multimedia.medialibrary.startup.";
39 constexpr uint32_t BASE_USER_RANGE = 200000;
40 const std::unordered_set<OperationObject> OPERATION_OBJECT_SET = {
41     OperationObject::UFM_PHOTO,
42     OperationObject::UFM_AUDIO,
43     OperationObject::PAH_PHOTO,
44     OperationObject::PAH_MAP,
45 };
46 const std::unordered_set<OperationType> OPERATION_TYPE_SET = {
47     OperationType::QUERY,
48 };
49 
GetTableNameFromOprnObject(const OperationObject & object)50 std::string GetTableNameFromOprnObject(const OperationObject& object)
51 {
52     CHECK_AND_RETURN_RET(object != OperationObject::PAH_MAP, PhotoColumn::PHOTOS_TABLE);
53     if (TABLE_NAME_MAP.find(object) != TABLE_NAME_MAP.end()) {
54         auto cmdObj = TABLE_NAME_MAP.at(object);
55         return cmdObj.begin()->second;
56     } else {
57         return MEDIALIBRARY_TABLE;
58     }
59 }
60 
GetOprnTypeFromUri(Uri & uri)61 OperationType GetOprnTypeFromUri(Uri& uri)
62 {
63     const std::string opType = MediaFileUri::GetPathSecondDentry(uri);
64     if (OPRN_TYPE_MAP.find(opType) != OPRN_TYPE_MAP.end()) {
65         return OPRN_TYPE_MAP.at(opType);
66     } else {
67         return OperationType::QUERY;
68     }
69 }
70 
GetOprnObjectFromUri(Uri & uri)71 OperationObject GetOprnObjectFromUri(Uri& uri)
72 {
73     const string opObject = MediaFileUri::GetPathFirstDentry(uri);
74     CHECK_AND_RETURN_RET(OPRN_OBJ_MAP.find(opObject) == OPRN_OBJ_MAP.end(),
75         OPRN_OBJ_MAP.at(opObject));
76     std::string uriString = uri.ToString();
77     CHECK_AND_RETURN_RET(!MediaFileUtils::StartsWith(uriString, PhotoColumn::PHOTO_CACHE_URI_PREFIX),
78         OperationObject::PAH_PHOTO);
79 
80     for (const auto &item : OPRN_MAP) {
81         CHECK_AND_RETURN_RET(!MediaFileUtils::StartsWith(uriString, item.first), item.second);
82     }
83     return OperationObject::UNKNOWN_OBJECT;
84 }
85 
GetInstance()86 MediaAssetRdbStore* MediaAssetRdbStore::GetInstance()
87 {
88     static MediaAssetRdbStore instance;
89     return &instance;
90 }
91 
CloudSyncTriggerFunc(const std::vector<std::string> & args)92 const std::string MediaAssetRdbStore::CloudSyncTriggerFunc(const std::vector<std::string>& args)
93 {
94     return "true";
95 }
96 
IsCallerSelfFunc(const std::vector<std::string> & args)97 const std::string MediaAssetRdbStore::IsCallerSelfFunc(const std::vector<std::string>& args)
98 {
99     return "false";
100 }
101 
PhotoAlbumNotifyFunc(const std::vector<std::string> & args)102 const std::string MediaAssetRdbStore::PhotoAlbumNotifyFunc(const std::vector<std::string> &args)
103 {
104     return "";
105 }
106 
MediaAssetRdbStore()107 MediaAssetRdbStore::MediaAssetRdbStore()
108 {
109     MEDIA_INFO_LOG("init visitor rdb");
110     CHECK_AND_RETURN_INFO_LOG(rdbStore_ == nullptr, "visitor rdb exists");
111     CHECK_AND_RETURN(TryGetRdbStore() == NativeRdb::E_OK);
112     MEDIA_INFO_LOG("success to init visitor rdb");
113 }
114 
TryGetRdbStore(bool isIgnoreSELinux)115 int32_t MediaAssetRdbStore::TryGetRdbStore(bool isIgnoreSELinux)
116 {
117     auto context = AbilityRuntime::Context::GetApplicationContext();
118     CHECK_AND_RETURN_RET_LOG(context != nullptr, NativeRdb::E_ERROR, "fail to acquire application Context");
119     uid_t uid = getuid() / BASE_USER_RANGE;
120     const string key = MEDIA_LIBRARY_STARTUP_PARAM_PREFIX + to_string(uid);
121     auto rdbInitFlag = system::GetBoolParameter(key, false);
122     bool cond = (!rdbInitFlag && !isIgnoreSELinux);
123     CHECK_AND_RETURN_RET_LOG(!cond, NativeRdb::E_ERROR,
124         "media library db update not complete, key:%{public}s", key.c_str());
125 
126     string name = MEDIA_DATA_ABILITY_DB_NAME;
127     string databaseDir = MEDIA_DB_DIR + "/rdb";
128     if (access(databaseDir.c_str(), E_OK) != 0) {
129         MEDIA_WARN_LOG("can not get rdb through sandbox");
130         return NativeRdb::E_ERROR;
131     }
132     string dbPath = databaseDir.append("/").append(name);
133     int32_t errCode = 0;
134     NativeRdb::RdbStoreConfig config {""};
135     config.SetName(name);
136     config.SetVisitorDir(dbPath);
137     config.SetBundleName(context->GetBundleName());
138     config.SetArea(context->GetArea());
139     config.SetSecurityLevel(SecurityLevel::S3);
140     config.SetRoleType(RoleType::VISITOR);
141     config.SetScalarFunction("cloud_sync_func", 0, CloudSyncTriggerFunc);
142     config.SetScalarFunction("is_caller_self_func", 0, IsCallerSelfFunc);
143     config.SetScalarFunction("photo_album_notify_func", 1, PhotoAlbumNotifyFunc);
144 
145     MediaLibraryDataCallBack rdbDataCallBack;
146     rdbStore_ = RdbHelper::GetRdbStore(config, MEDIA_RDB_VERSION, rdbDataCallBack, errCode);
147     if (rdbStore_ == nullptr || errCode != NativeRdb::E_OK) {
148         MEDIA_WARN_LOG("Failed to get visitor RdbStore, errCode: %{public}d", errCode);
149         rdbStore_ = nullptr;
150         return errCode;
151     }
152     return NativeRdb::E_OK;
153 }
154 
AddVirtualColumnsOfDateType(vector<string> & columns)155 void AddVirtualColumnsOfDateType(vector<string>& columns)
156 {
157     vector<string> dateTypes = { MEDIA_DATA_DB_DATE_ADDED, MEDIA_DATA_DB_DATE_TRASHED, MEDIA_DATA_DB_DATE_MODIFIED,
158             MEDIA_DATA_DB_DATE_TAKEN };
159     vector<string> dateTypeSeconds = { MEDIA_DATA_DB_DATE_ADDED_TO_SECOND,
160             MEDIA_DATA_DB_DATE_TRASHED_TO_SECOND, MEDIA_DATA_DB_DATE_MODIFIED_TO_SECOND,
161             MEDIA_DATA_DB_DATE_TAKEN_TO_SECOND };
162     for (size_t i = 0; i < dateTypes.size(); i++) {
163         auto it = find(columns.begin(), columns.end(), dateTypes[i]);
164         if (it != columns.end()) {
165             columns.push_back(dateTypeSeconds[i]);
166         }
167     }
168 }
169 
AddQueryIndex(AbsPredicates & predicates,const vector<string> & columns)170 void AddQueryIndex(AbsPredicates& predicates, const vector<string>& columns)
171 {
172     auto it = find(columns.begin(), columns.end(), MEDIA_COLUMN_COUNT);
173     if (it == columns.end()) {
174         return;
175     }
176     const string &group = predicates.GetGroup();
177     const string &whereInfo = predicates.GetWhereClause();
178     if (group.empty()) {
179         predicates.GroupBy({ PhotoColumn::PHOTO_DATE_DAY });
180         predicates.IndexedBy(PhotoColumn::PHOTO_SCHPT_DAY_INDEX);
181         return;
182     }
183     if (group == PhotoColumn::MEDIA_TYPE && (whereInfo.find(PhotoColumn::PHOTO_THUMBNAIL_VISIBLE) == string::npos)) {
184         predicates.IndexedBy(PhotoColumn::PHOTO_SCHPT_MEDIA_TYPE_INDEX);
185         return;
186     }
187     if (group == PhotoColumn::PHOTO_DATE_DAY) {
188         predicates.IndexedBy(PhotoColumn::PHOTO_SCHPT_DAY_INDEX);
189         return;
190     }
191 }
192 
GetQueryFilter(const string & tableName)193 static string GetQueryFilter(const string &tableName)
194 {
195     if (tableName == MEDIALIBRARY_TABLE) {
196         return MEDIALIBRARY_TABLE + "." + MEDIA_DATA_DB_SYNC_STATUS + " = " +
197             to_string(static_cast<int32_t>(SyncStatusType::TYPE_VISIBLE));
198     }
199     if (tableName == PhotoColumn::PHOTOS_TABLE) {
200         return PhotoColumn::PHOTOS_TABLE + "." + PhotoColumn::PHOTO_SYNC_STATUS + " = " +
201             to_string(static_cast<int32_t>(SyncStatusType::TYPE_VISIBLE)) + " AND " +
202             PhotoColumn::PHOTOS_TABLE + "." + PhotoColumn::PHOTO_CLEAN_FLAG + " = " +
203             to_string(static_cast<int32_t>(CleanType::TYPE_NOT_CLEAN));
204     }
205     if (tableName == PhotoAlbumColumns::TABLE) {
206         return PhotoAlbumColumns::TABLE + "." + PhotoAlbumColumns::ALBUM_DIRTY + " != " +
207             to_string(static_cast<int32_t>(DirtyTypes::TYPE_DELETED));
208     }
209     if (tableName == PhotoMap::TABLE) {
210         return PhotoMap::TABLE + "." + PhotoMap::DIRTY + " != " + to_string(static_cast<int32_t>(
211             DirtyTypes::TYPE_DELETED));
212     }
213     return "";
214 }
215 
AddQueryFilter(AbsRdbPredicates & predicates)216 void AddQueryFilter(AbsRdbPredicates &predicates)
217 {
218     /* build all-table vector */
219     string tableName = predicates.GetTableName();
220     vector<string> joinTables = predicates.GetJoinTableNames();
221     joinTables.push_back(tableName);
222     /* add filters */
223     string filters;
224     for (auto &t : joinTables) {
225         string filter = GetQueryFilter(t);
226         if (filter.empty()) {
227             continue;
228         }
229         if (filters.empty()) {
230             filters += filter;
231         } else {
232             filters += " AND " + filter;
233         }
234     }
235     if (filters.empty()) {
236         return;
237     }
238 
239     /* rebuild */
240     string queryCondition = predicates.GetWhereClause();
241     MEDIA_DEBUG_LOG("queryCondition: %{public}s", queryCondition.c_str());
242     queryCondition = queryCondition.empty() ? filters : filters + " AND " + queryCondition;
243     predicates.SetWhereClause(queryCondition);
244 }
245 
Query(const DataShare::DataSharePredicates & predicates,std::vector<std::string> & columns,OperationObject & object,int & errCode)246 std::shared_ptr<DataShare::DataShareResultSet> MediaAssetRdbStore::Query(
247     const DataShare::DataSharePredicates& predicates,
248     std::vector<std::string>& columns, OperationObject& object, int& errCode)
249 {
250     auto resultSet = QueryRdb(predicates, columns, object);
251     CHECK_AND_RETURN_RET_LOG(resultSet != nullptr, nullptr, "fail to acquire result from visitor query");
252     auto resultSetBridge = RdbUtils::ToResultSetBridge(resultSet);
253     return make_shared<DataShare::DataShareResultSet>(resultSetBridge);
254 }
255 
IsNumber(const string & str)256 bool IsNumber(const string& str)
257 {
258     CHECK_AND_RETURN_RET_LOG(!str.empty(), false, "IsNumber input is empty");
259     for (char const& c : str) {
260         CHECK_AND_RETURN_RET(isdigit(c) != 0, false);
261     }
262     return true;
263 }
264 
GetInt32Val(const string & column,std::shared_ptr<NativeRdb::AbsSharedResultSet> & resultSet)265 int32_t GetInt32Val(const string& column, std::shared_ptr<NativeRdb::AbsSharedResultSet>& resultSet)
266 {
267     int index;
268     int32_t value = -1;
269     int err = resultSet->GetColumnIndex(column, index);
270     if (err == E_OK) {
271         err = resultSet->GetInt(index, value);
272     }
273     return value;
274 }
275 
IsQueryGroupPhotoAlbumAssets(const string & albumId)276 bool MediaAssetRdbStore::IsQueryGroupPhotoAlbumAssets(const string &albumId)
277 {
278     bool cond = (albumId.empty() || !IsNumber(albumId));
279     CHECK_AND_RETURN_RET(!cond, false);
280     RdbPredicates predicates(ANALYSIS_ALBUM_TABLE);
281     predicates.EqualTo(PhotoAlbumColumns::ALBUM_ID, albumId);
282     vector<string> columns = {PhotoAlbumColumns::ALBUM_TYPE, PhotoAlbumColumns::ALBUM_SUBTYPE};
283     auto resultSet = rdbStore_->Query(predicates, columns);
284 
285     cond = (resultSet == nullptr || resultSet->GoToFirstRow() != E_OK);
286     CHECK_AND_RETURN_RET(!cond, false);
287     int32_t albumType = GetInt32Val(PhotoAlbumColumns::ALBUM_TYPE, resultSet);
288     int32_t albumSubtype = GetInt32Val(PhotoAlbumColumns::ALBUM_SUBTYPE, resultSet);
289     return albumType == PhotoAlbumType::SMART && albumSubtype == PhotoAlbumSubType::GROUP_PHOTO;
290 }
291 
IsQueryAccessibleViaSandBox(Uri & uri,OperationObject & object,const DataShare::DataSharePredicates & predicates,bool isIgnoreSELinux)292 bool MediaAssetRdbStore::IsQueryAccessibleViaSandBox(Uri& uri, OperationObject& object,
293     const DataShare::DataSharePredicates& predicates, bool isIgnoreSELinux)
294 {
295     CHECK_AND_RETURN_RET(access(MEDIA_DB_DIR.c_str(), E_OK) == 0, false);
296     if (rdbStore_ == nullptr) {
297         CHECK_AND_RETURN_RET_LOG(TryGetRdbStore(isIgnoreSELinux) == NativeRdb::E_OK, false,
298             "fail to acquire rdb when query");
299     }
300 
301     object = GetOprnObjectFromUri(uri);
302     CHECK_AND_RETURN_RET(OPERATION_OBJECT_SET.count(object) != 0, false);
303     OperationType type = GetOprnTypeFromUri(uri);
304     CHECK_AND_RETURN_RET(OPERATION_TYPE_SET.count(type) != 0, false);
305     CHECK_AND_RETURN_RET(object == OperationObject::PAH_MAP, true);
306 
307     std::string tableName = GetTableNameFromOprnObject(object);
308     NativeRdb::RdbPredicates rdbPredicates = RdbUtils::ToPredicates(predicates, tableName);
309     auto whereArgs = rdbPredicates.GetWhereArgs();
310     if (!whereArgs.empty()) {
311         string albumId = whereArgs[0];
312         CHECK_AND_RETURN_RET(!IsQueryGroupPhotoAlbumAssets(albumId), false);
313     }
314     return true;
315 }
316 
AddQueryDateTakenTime(std::vector<std::string> & columns)317 std::shared_ptr<NativeRdb::AbsSharedResultSet> MediaAssetRdbStore::AddQueryDateTakenTime(
318     std::vector<std::string>& columns)
319 {
320     auto it = find(columns.begin(), columns.end(), MEDIA_COLUMN_COUNT);
321     CHECK_AND_RETURN_RET(it != columns.end(), nullptr);
322     auto itData = find(columns.begin(), columns.end(), MEDIA_DATA_DB_DATE_TAKEN);
323     CHECK_AND_RETURN_RET(itData != columns.end(), nullptr);
324     std::string extraWhereSql = "";
325     auto itForThumbnailVisible = find(columns.begin(), columns.end(), PhotoColumn::PHOTO_THUMBNAIL_VISIBLE);
326     if (itForThumbnailVisible != columns.end()) {
327         extraWhereSql = " AND thumbnail_visible = 1 ";
328     }
329 
330     std::string sql = ""
331         "SELECT"
332         "  count( * ) AS count,"
333         "  date_taken,"
334         "  date_day,"
335         "  burst_key,"
336         "  display_name,"
337         "  file_id,"
338         "  media_type,"
339         "  subtype "
340         "FROM"
341         "  Photos "
342         "WHERE"
343         "  sync_status = 0 "
344         "  AND clean_flag = 0 "
345         "  AND date_trashed = 0 "
346         "  AND time_pending = 0 "
347         "  AND hidden = 0 "
348         "  AND is_temp = 0 "
349         "  AND burst_cover_level = 1 " +
350         extraWhereSql +
351         "GROUP BY"
352         "  date_day "
353         "ORDER BY"
354         "  date_day DESC;";
355 
356     auto resultSet = rdbStore_->QuerySql(sql);
357     CHECK_AND_RETURN_RET_LOG(resultSet != nullptr, nullptr, "fail to acquire result from visitor query");
358     return resultSet;
359 }
360 
QueryRdb(const DataShare::DataSharePredicates & predicates,std::vector<std::string> & columns,OperationObject & object)361 std::shared_ptr<NativeRdb::ResultSet> MediaAssetRdbStore::QueryRdb(
362     const DataShare::DataSharePredicates& predicates, std::vector<std::string>& columns, OperationObject& object)
363 {
364     CHECK_AND_RETURN_RET_LOG(rdbStore_ != nullptr, nullptr, "fail to acquire rdb when query");
365     auto ret = AddQueryDateTakenTime(columns);
366     CHECK_AND_RETURN_RET(ret == nullptr, ret);
367     std::string tableName = GetTableNameFromOprnObject(object);
368     NativeRdb::RdbPredicates rdbPredicates = RdbUtils::ToPredicates(predicates, tableName);
369     AddVirtualColumnsOfDateType(const_cast<vector<string> &>(columns));
370     if (object == OperationObject::UFM_PHOTO || object == OperationObject::PAH_PHOTO) {
371         AddQueryIndex(rdbPredicates, columns);
372     }
373 
374     AddQueryFilter(rdbPredicates);
375     auto resultSet = rdbStore_->QueryByStep(rdbPredicates, columns, false);
376     CHECK_AND_RETURN_RET_LOG(resultSet != nullptr, nullptr, "fail to acquire result from visitor query");
377     return resultSet;
378 }
379 
IsSupportSharedAssetQuery(Uri & uri,OperationObject & object,bool isIgnoreSELinux)380 bool MediaAssetRdbStore::IsSupportSharedAssetQuery(Uri& uri, OperationObject& object, bool isIgnoreSELinux)
381 {
382     CHECK_AND_RETURN_RET(access(MEDIA_DB_DIR.c_str(), E_OK) == 0, false);
383     if (rdbStore_ == nullptr) {
384         CHECK_AND_RETURN_RET_LOG(TryGetRdbStore(isIgnoreSELinux) == NativeRdb::E_OK, false,
385             "fail to acquire rdb when query");
386     }
387 
388     OperationType type = GetOprnTypeFromUri(uri);
389     CHECK_AND_RETURN_RET(OPERATION_TYPE_SET.count(type) != 0, false);
390     object = GetOprnObjectFromUri(uri);
391     return true;
392 }
393 
QueryTimeIdBatch(int32_t start,int32_t count,std::vector<std::string> & batchKeys)394 int32_t MediaAssetRdbStore::QueryTimeIdBatch(int32_t start, int32_t count, std::vector<std::string> &batchKeys)
395 {
396     MediaLibraryTracer tracer;
397     tracer.Start("MediaAssetRdbStore::QueryTimeIdBatch");
398     CHECK_AND_RETURN_RET_LOG(rdbStore_ != nullptr, NativeRdb::E_DB_NOT_EXIST, "rdbStore_ is nullptr when query");
399     DataShare::DataSharePredicates predicates;
400     predicates.And()->OrderByDesc(MediaColumn::MEDIA_DATE_TAKEN)
401                     ->Limit(count, start)
402                     ->EqualTo(PhotoColumn::PHOTO_THUMBNAIL_VISIBLE, "1")
403                     ->EqualTo(MediaColumn::MEDIA_DATE_TRASHED, "0")
404                     ->EqualTo(MediaColumn::MEDIA_TIME_PENDING, "0")
405                     ->EqualTo(MediaColumn::MEDIA_HIDDEN, "0")
406                     ->EqualTo(PhotoColumn::PHOTO_IS_TEMP, "0")
407                     ->EqualTo(PhotoColumn::PHOTO_BURST_COVER_LEVEL,
408                         to_string(static_cast<int32_t>(BurstCoverLevelType::COVER)));
409     std::vector<std::string> columns = {MediaColumn::MEDIA_ID, MediaColumn::MEDIA_DATE_TAKEN};
410     NativeRdb::RdbPredicates rdbPredicates = RdbUtils::ToPredicates(predicates, PhotoColumn::PHOTOS_TABLE);
411     AddQueryFilter(rdbPredicates);
412     auto resultSet = rdbStore_->Query(rdbPredicates, columns);
413     CHECK_AND_RETURN_RET_LOG(resultSet != nullptr, NativeRdb::E_ERROR, "fail to acquire result from visitor query");
414 
415     while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
416         int columnIndex = 0;
417         int64_t dateTakenTime = 0;
418         int fileId = 0;
419         if (resultSet->GetColumnIndex(MediaColumn::MEDIA_DATE_TAKEN, columnIndex) != NativeRdb::E_OK ||
420             resultSet->GetLong(columnIndex, dateTakenTime) != NativeRdb::E_OK) {
421             MEDIA_ERR_LOG("Fail to get dateTaken");
422             return NativeRdb::E_ERROR;
423         }
424         if (resultSet->GetColumnIndex(MediaColumn::MEDIA_ID, columnIndex) != NativeRdb::E_OK ||
425             resultSet->GetInt(columnIndex, fileId) != NativeRdb::E_OK) {
426             MEDIA_ERR_LOG("Fail to get fileId");
427             return NativeRdb::E_ERROR;
428         }
429 
430         std::string timeId;
431         if (!MediaFileUtils::GenerateKvStoreKey(to_string(fileId), to_string(dateTakenTime), timeId)) {
432             MEDIA_ERR_LOG("Fail to generate kvStore key, fileId:%{public}d", fileId);
433             continue;
434         }
435         batchKeys.emplace_back(std::move(timeId));
436     }
437     return NativeRdb::E_OK;
438 }
439 
OnCreate(NativeRdb::RdbStore & rdbStore)440 int32_t MediaLibraryDataCallBack::OnCreate(NativeRdb::RdbStore& rdbStore)
441 {
442     return 0;
443 }
444 
OnUpgrade(NativeRdb::RdbStore & rdbStore,int32_t oldVersion,int32_t newVersion)445 int32_t MediaLibraryDataCallBack::OnUpgrade(NativeRdb::RdbStore& rdbStore, int32_t oldVersion, int32_t newVersion)
446 {
447     return 0;
448 }
449 
450 } // namespace Media
451 } // namespace OHOS