1 /*
2 * Copyright (C) 2021-2023 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 "MediaLibraryManager"
16
17 #include "media_library_manager.h"
18
19 #include <fcntl.h>
20 #include <unistd.h>
21
22 #include "album_asset.h"
23 #include "fetch_result.h"
24 #include "file_asset.h"
25 #include "datashare_abs_result_set.h"
26 #include "datashare_predicates.h"
27 #include "image_source.h"
28 #include "media_file_uri.h"
29 #include "media_file_utils.h"
30 #include "media_log.h"
31 #include "medialibrary_db_const.h"
32 #include "medialibrary_errno.h"
33 #include "medialibrary_tracer.h"
34 #include "medialibrary_type_const.h"
35 #include "result_set_utils.h"
36 #include "string_ex.h"
37 #include "unique_fd.h"
38
39 using namespace std;
40 using namespace OHOS::NativeRdb;
41
42 namespace OHOS {
43 namespace Media {
44 shared_ptr<DataShare::DataShareHelper> MediaLibraryManager::sDataShareHelper_ = nullptr;
45 const string THUMBNAIL_PATH = "path";
46 const string THUMBNAIL_HEIGHT = "height";
47 const string THUMBNAIL_WIDTH = "width";
48 constexpr int32_t DEFAULT_THUMBNAIL_SIZE = 256;
49
GetMediaLibraryManager()50 MediaLibraryManager *MediaLibraryManager::GetMediaLibraryManager()
51 {
52 static MediaLibraryManager mediaLibMgr;
53 return &mediaLibMgr;
54 }
55
InitMediaLibraryManager(const sptr<IRemoteObject> & token)56 void MediaLibraryManager::InitMediaLibraryManager(const sptr<IRemoteObject> &token)
57 {
58 if (sDataShareHelper_ == nullptr) {
59 sDataShareHelper_ = DataShare::DataShareHelper::Creator(token, MEDIALIBRARY_DATA_URI);
60 }
61 }
62
CloseAsset(const string & uri,const int32_t fd)63 int32_t MediaLibraryManager::CloseAsset(const string &uri, const int32_t fd)
64 {
65 int32_t retVal = E_FAIL;
66 DataShareValuesBucket valuesBucket;
67 valuesBucket.Put(MEDIA_DATA_DB_URI, uri);
68
69 if (sDataShareHelper_ != nullptr) {
70 string abilityUri = MEDIALIBRARY_DATA_URI;
71 Uri closeAssetUri(abilityUri + "/" + MEDIA_FILEOPRN + "/" + MEDIA_FILEOPRN_CLOSEASSET);
72
73 if (close(fd) == E_SUCCESS) {
74 retVal = sDataShareHelper_->Insert(closeAssetUri, valuesBucket);
75 }
76
77 if (retVal == E_FAIL) {
78 MEDIA_ERR_LOG("Failed to close the file");
79 }
80 }
81
82 return retVal;
83 }
84
QueryTotalSize(MediaVolume & outMediaVolume)85 int32_t MediaLibraryManager::QueryTotalSize(MediaVolume &outMediaVolume)
86 {
87 if (sDataShareHelper_ == nullptr) {
88 MEDIA_ERR_LOG("sDataShareHelper_ is null");
89 return E_FAIL;
90 }
91 vector<string> columns;
92 Uri uri(MEDIALIBRARY_DATA_URI + "/" + MEDIA_QUERYOPRN_QUERYVOLUME + "/" + MEDIA_QUERYOPRN_QUERYVOLUME);
93 DataSharePredicates predicates;
94 auto queryResultSet = sDataShareHelper_->Query(uri, predicates, columns);
95 if (queryResultSet == nullptr) {
96 MEDIA_ERR_LOG("queryResultSet is null!");
97 return E_FAIL;
98 }
99 auto count = 0;
100 auto ret = queryResultSet->GetRowCount(count);
101 if (ret != NativeRdb::E_OK) {
102 MEDIA_ERR_LOG("get rdbstore failed");
103 return E_HAS_DB_ERROR;
104 }
105 MEDIA_INFO_LOG("count = %{public}d", (int)count);
106 if (count >= 0) {
107 while (queryResultSet->GoToNextRow() == NativeRdb::E_OK) {
108 int mediatype = get<int32_t>(ResultSetUtils::GetValFromColumn(MEDIA_DATA_DB_MEDIA_TYPE,
109 queryResultSet, TYPE_INT32));
110 int64_t size = get<int64_t>(ResultSetUtils::GetValFromColumn(MEDIA_DATA_DB_SIZE,
111 queryResultSet, TYPE_INT64));
112 outMediaVolume.SetSize(mediatype, size);
113 }
114 }
115 MEDIA_INFO_LOG("Size:Files:%{public}" PRId64 " Videos:%{public}" PRId64 " Images:%{public} " PRId64
116 " Audio:%{public}" PRId64,
117 outMediaVolume.GetFilesSize(), outMediaVolume.GetVideosSize(),
118 outMediaVolume.GetImagesSize(), outMediaVolume.GetAudiosSize());
119 return E_SUCCESS;
120 }
121
GetResultSetFromDb(string columnName,const string & value,vector<string> & columns)122 std::shared_ptr<DataShareResultSet> MediaLibraryManager::GetResultSetFromDb(string columnName, const string &value,
123 vector<string> &columns)
124 {
125 Uri uri(MEDIALIBRARY_MEDIA_PREFIX);
126 DataSharePredicates predicates;
127 predicates.EqualTo(columnName, value);
128 predicates.And()->EqualTo(MEDIA_DATA_DB_IS_TRASH, to_string(NOT_TRASHED));
129 DatashareBusinessError businessError;
130
131 if (sDataShareHelper_ == nullptr) {
132 MEDIA_ERR_LOG("sDataShareHelper_ is null");
133 return nullptr;
134 }
135 return sDataShareHelper_->Query(uri, predicates, columns, &businessError);
136 }
137
SolvePath(const string & filePath,string & tempPath,string & userId)138 static int32_t SolvePath(const string &filePath, string &tempPath, string &userId)
139 {
140 if (filePath.empty()) {
141 return E_INVALID_PATH;
142 }
143
144 string prePath = PRE_PATH_VALUES;
145 if (filePath.find(prePath) != 0) {
146 return E_CHECK_ROOT_DIR_FAIL;
147 }
148 string postpath = filePath.substr(prePath.length());
149 auto pos = postpath.find('/');
150 if (pos == string::npos) {
151 return E_INVALID_ARGUMENTS;
152 }
153 userId = postpath.substr(0, pos);
154 postpath = postpath.substr(pos + 1);
155 tempPath = prePath + postpath;
156
157 return E_SUCCESS;
158 }
159
CheckResultSet(std::shared_ptr<DataShareResultSet> & resultSet)160 static int32_t CheckResultSet(std::shared_ptr<DataShareResultSet> &resultSet)
161 {
162 int count = 0;
163 auto ret = resultSet->GetRowCount(count);
164 if (ret != NativeRdb::E_OK) {
165 MEDIA_ERR_LOG("Failed to get resultset row count, ret: %{public}d", ret);
166 return ret;
167 }
168 if (count <= 0) {
169 MEDIA_ERR_LOG("Failed to get count, count: %{public}d", count);
170 return E_FAIL;
171 }
172 ret = resultSet->GoToFirstRow();
173 if (ret != NativeRdb::E_OK) {
174 MEDIA_ERR_LOG("Failed to go to first row, ret: %{public}d", ret);
175 return ret;
176 }
177 return E_SUCCESS;
178 }
179
180
GetFilePathFromUri(const Uri & fileUri,string & filePath,string userId)181 int32_t MediaLibraryManager::GetFilePathFromUri(const Uri &fileUri, string &filePath, string userId)
182 {
183 string uri = fileUri.ToString();
184 MediaFileUri virtualUri(uri);
185 if (!virtualUri.IsValid()) {
186 return E_URI_INVALID;
187 }
188 string virtualId = virtualUri.GetFileId();
189 #ifdef MEDIALIBRARY_COMPATIBILITY
190 if (MediaFileUtils::GetTableFromVirtualUri(uri) != MEDIALIBRARY_TABLE) {
191 MEDIA_INFO_LOG("uri:%{private}s does not match Files Table", uri.c_str());
192 return E_URI_INVALID;
193 }
194 #endif
195 vector<string> columns = { MEDIA_DATA_DB_FILE_PATH };
196 auto resultSet = MediaLibraryManager::GetResultSetFromDb(MEDIA_DATA_DB_ID, virtualId, columns);
197 CHECK_AND_RETURN_RET_LOG(resultSet != nullptr, E_INVALID_URI,
198 "GetFilePathFromUri::uri is not correct: %{public}s", uri.c_str());
199 if (CheckResultSet(resultSet) != E_SUCCESS) {
200 return E_FAIL;
201 }
202
203 std::string tempPath = ResultSetUtils::GetStringValFromColumn(1, resultSet);
204 if (tempPath.find(ROOT_MEDIA_DIR) != 0) {
205 return E_CHECK_ROOT_DIR_FAIL;
206 }
207 string relativePath = tempPath.substr(ROOT_MEDIA_DIR.length());
208 auto pos = relativePath.find('/');
209 if (pos == string::npos) {
210 return E_INVALID_ARGUMENTS;
211 }
212 relativePath = relativePath.substr(0, pos + 1);
213 if ((relativePath != DOC_DIR_VALUES) && (relativePath != DOWNLOAD_DIR_VALUES)) {
214 return E_DIR_CHECK_DIR_FAIL;
215 }
216
217 string prePath = PRE_PATH_VALUES;
218 string postpath = tempPath.substr(prePath.length());
219 tempPath = prePath + userId + "/" + postpath;
220 filePath = tempPath;
221 return E_SUCCESS;
222 }
223
GetUriFromFilePath(const string & filePath,Uri & fileUri,string & userId)224 int32_t MediaLibraryManager::GetUriFromFilePath(const string &filePath, Uri &fileUri, string &userId)
225 {
226 if (filePath.empty()) {
227 return E_INVALID_PATH;
228 }
229
230 string tempPath;
231 SolvePath(filePath, tempPath, userId);
232 if (tempPath.find(ROOT_MEDIA_DIR) != 0) {
233 return E_CHECK_ROOT_DIR_FAIL;
234 }
235 string relativePath = tempPath.substr(ROOT_MEDIA_DIR.length());
236 auto pos = relativePath.find('/');
237 if (pos == string::npos) {
238 return E_INVALID_ARGUMENTS;
239 }
240 relativePath = relativePath.substr(0, pos + 1);
241 if ((relativePath != DOC_DIR_VALUES) && (relativePath != DOWNLOAD_DIR_VALUES)) {
242 return E_DIR_CHECK_DIR_FAIL;
243 }
244
245 vector<string> columns = { MEDIA_DATA_DB_ID};
246 auto resultSet = MediaLibraryManager::GetResultSetFromDb(MEDIA_DATA_DB_FILE_PATH, tempPath, columns);
247 CHECK_AND_RETURN_RET_LOG(resultSet != nullptr, E_INVALID_URI,
248 "GetUriFromFilePath::tempPath is not correct: %{public}s", tempPath.c_str());
249 if (CheckResultSet(resultSet) != E_SUCCESS) {
250 return E_FAIL;
251 }
252
253 int32_t fileId = ResultSetUtils::GetIntValFromColumn(0, resultSet);
254 #ifdef MEDIALIBRARY_COMPATIBILITY
255 int64_t virtualId = MediaFileUtils::GetVirtualIdByType(fileId, MediaType::MEDIA_TYPE_FILE);
256 fileUri = MediaFileUri(MediaType::MEDIA_TYPE_FILE, to_string(virtualId), "", MEDIA_API_VERSION_V9);
257 #else
258 fileUri = MediaFileUri(MediaType::MEDIA_TYPE_FILE, to_string(fileId), "", MEDIA_API_VERSION_V9);
259 #endif
260 return E_SUCCESS;
261 }
262
IsThumbnail(const int32_t width,const int32_t height)263 static inline bool IsThumbnail(const int32_t width, const int32_t height)
264 {
265 return (width <= DEFAULT_THUMBNAIL_SIZE) && (height <= DEFAULT_THUMBNAIL_SIZE);
266 }
267
GetSandboxPath(const std::string & path,bool isThumb)268 static inline std::string GetSandboxPath(const std::string &path, bool isThumb)
269 {
270 if (path.length() < ROOT_MEDIA_DIR.length()) {
271 return "";
272 }
273 std::string suffixStr = path.substr(ROOT_MEDIA_DIR.length()) + (isThumb ? "/THM.jpg" : "/LCD.jpg");
274 return ROOT_SANDBOX_DIR + ".thumbs/" + suffixStr;
275 }
276
OpenThumbnail(string & uriStr,const string & path,const Size & size)277 int MediaLibraryManager::OpenThumbnail(string &uriStr, const string &path, const Size &size)
278 {
279 if (!path.empty()) {
280 string sandboxPath = GetSandboxPath(path, IsThumbnail(size.width, size.height));
281 int fd = -1;
282 if (!sandboxPath.empty()) {
283 fd = open(sandboxPath.c_str(), O_RDONLY);
284 }
285 if (fd > 0) {
286 return fd;
287 }
288 if (IsAsciiString(path)) {
289 uriStr += "&" + THUMBNAIL_PATH + "=" + path;
290 }
291 }
292 Uri openUri(uriStr);
293 return sDataShareHelper_->OpenFile(openUri, "R");
294 }
295
296 /**
297 * Get the file uri prefix with id
298 * eg. Input: file://media/Photo/10/IMG_xxx/01.jpg
299 * Output: file://media/Photo/10
300 */
GetUriIdPrefix(std::string & fileUri)301 static void GetUriIdPrefix(std::string &fileUri)
302 {
303 MediaFileUri mediaUri(fileUri);
304 if (!mediaUri.IsApi10()) {
305 return;
306 }
307 auto slashIdx = fileUri.rfind('/');
308 if (slashIdx == std::string::npos) {
309 return;
310 }
311 auto tmpUri = fileUri.substr(0, slashIdx);
312 slashIdx = tmpUri.rfind('/');
313 if (slashIdx == std::string::npos) {
314 return;
315 }
316 fileUri = tmpUri.substr(0, slashIdx);
317 }
318
GetParamsFromUri(const string & uri,string & fileUri,const bool isOldVer,Size & size,string & path)319 static bool GetParamsFromUri(const string &uri, string &fileUri, const bool isOldVer, Size &size, string &path)
320 {
321 MediaFileUri mediaUri(uri);
322 if (!mediaUri.IsValid()) {
323 return false;
324 }
325 if (isOldVer) {
326 auto index = uri.find("thumbnail");
327 if (index == string::npos) {
328 return false;
329 }
330 fileUri = uri.substr(0, index - 1);
331 GetUriIdPrefix(fileUri);
332 index += strlen("thumbnail");
333 index = uri.find('/', index);
334 if (index == string::npos) {
335 return false;
336 }
337 index += 1;
338 auto tmpIdx = uri.find('/', index);
339 if (tmpIdx == string::npos) {
340 return false;
341 }
342
343 int32_t width = 0;
344 StrToInt(uri.substr(index, tmpIdx - index), width);
345 int32_t height = 0;
346 StrToInt(uri.substr(tmpIdx + 1), height);
347 size = { .width = width, .height = height };
348 } else {
349 auto qIdx = uri.find('?');
350 if (qIdx == string::npos) {
351 return false;
352 }
353 fileUri = uri.substr(0, qIdx);
354 GetUriIdPrefix(fileUri);
355 auto &queryKey = mediaUri.GetQueryKeys();
356 if (queryKey.count(THUMBNAIL_PATH) != 0) {
357 path = queryKey[THUMBNAIL_PATH];
358 }
359 if (queryKey.count(THUMBNAIL_WIDTH) != 0) {
360 size.width = stoi(queryKey[THUMBNAIL_WIDTH]);
361 }
362 if (queryKey.count(THUMBNAIL_HEIGHT) != 0) {
363 size.height = stoi(queryKey[THUMBNAIL_HEIGHT]);
364 }
365 }
366 return true;
367 }
368
QueryThumbnail(const std::string & uri,Size & size,const string & path)369 static unique_ptr<PixelMap> QueryThumbnail(const std::string &uri, Size &size, const string &path)
370 {
371 MediaLibraryTracer tracer;
372 tracer.Start("QueryThumbnail uri:" + uri);
373
374 string openUriStr = uri + "?" + MEDIA_OPERN_KEYWORD + "=" + MEDIA_DATA_DB_THUMBNAIL + "&" + MEDIA_DATA_DB_WIDTH +
375 "=" + to_string(size.width) + "&" + MEDIA_DATA_DB_HEIGHT + "=" + to_string(size.height);
376 tracer.Start("DataShare::OpenThumbnail");
377 UniqueFd uniqueFd(MediaLibraryManager::OpenThumbnail(openUriStr, path, size));
378 if (uniqueFd.Get() < 0) {
379 MEDIA_ERR_LOG("queryThumb is null, errCode is %{public}d", uniqueFd.Get());
380 return nullptr;
381 }
382 tracer.Finish();
383 tracer.Start("ImageSource::CreateImageSource");
384 SourceOptions opts;
385 uint32_t err = 0;
386 unique_ptr<ImageSource> imageSource = ImageSource::CreateImageSource(uniqueFd.Get(), opts, err);
387 if (imageSource == nullptr) {
388 MEDIA_ERR_LOG("CreateImageSource err %{public}d", err);
389 return nullptr;
390 }
391
392 DecodeOptions decodeOpts;
393 decodeOpts.desiredSize = size;
394 decodeOpts.allocatorType = AllocatorType::SHARE_MEM_ALLOC;
395 #ifndef IMAGE_PURGEABLE_PIXELMAP
396 return imageSource->CreatePixelMap(decodeOpts, err);
397 #else
398 unique_ptr<PixelMap> pixelMap = imageSource->CreatePixelMap(decodeOpts, err);
399 uint32_t errorCode = 0;
400 unique_ptr<ImageSource> backupImgSrc = ImageSource::CreateImageSource(uniqueFd.Get(), opts, errorCode);
401 if (errorCode == Media::SUCCESS) {
402 PurgeableBuilder::MakePixelMapToBePurgeable(pixelMap, backupImgSrc, decodeOpts);
403 } else {
404 MEDIA_ERR_LOG("Failed to backup image source when to be purgeable: %{public}d", errorCode);
405 }
406
407 return pixelMap;
408 #endif
409 }
410
GetThumbnail(const Uri & uri)411 std::unique_ptr<PixelMap> MediaLibraryManager::GetThumbnail(const Uri &uri)
412 {
413 // uri is dataability:///media/image/<id>/thumbnail/<width>/<height>
414 string uriStr = uri.ToString();
415 auto thumbLatIdx = uriStr.find("thumbnail") + strlen("thumbnail");
416 if (thumbLatIdx == string::npos || thumbLatIdx > uriStr.length()) {
417 return nullptr;
418 }
419 bool isOldVersion = uriStr[thumbLatIdx] == '/';
420 string path;
421 string fileUri;
422 Size size;
423 if (!GetParamsFromUri(uriStr, fileUri, isOldVersion, size, path)) {
424 return nullptr;
425 }
426 return QueryThumbnail(fileUri, size, path);
427 }
428 } // namespace Media
429 } // namespace OHOS
430