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