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