• 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 <vector>
17 #include <map>
18 #include "medialibrary_app_uri_permission_operations.h"
19 #include "medialibrary_unistore_manager.h"
20 #include "medialibrary_rdbstore.h"
21 #include "medialibrary_rdb_utils.h"
22 #include "media_column.h"
23 #include "datashare_predicates.h"
24 #include "rdb_utils.h"
25 #include "media_file_uri.h"
26 #include "medialibrary_asset_operations.h"
27 #include "medialibrary_rdb_transaction.h"
28 #include "media_file_utils.h"
29 #include "medialibrary_appstate_observer.h"
30 #include "datashare_predicates_objects.h"
31 
32 using namespace OHOS::DataShare;
33 using namespace std;
34 using namespace OHOS::NativeRdb;
35 using namespace OHOS::RdbDataShareAdapter;
36 
37 namespace OHOS {
38 namespace Media {
39 
40 const int MediaLibraryAppUriPermissionOperations::ERROR = -1;
41 const int MediaLibraryAppUriPermissionOperations::SUCCEED = 0;
42 const int MediaLibraryAppUriPermissionOperations::ALREADY_EXIST = 1;
43 const int MediaLibraryAppUriPermissionOperations::NO_DATA_EXIST = 0;
44 
HandleInsertOperation(MediaLibraryCommand & cmd)45 int32_t MediaLibraryAppUriPermissionOperations::HandleInsertOperation(MediaLibraryCommand &cmd)
46 {
47     MEDIA_INFO_LOG("insert appUriPermission begin");
48     // permissionType from param
49     int permissionTypeParam = -1;
50     if (!GetIntFromValuesBucket(cmd.GetValueBucket(), AppUriPermissionColumn::PERMISSION_TYPE,
51         permissionTypeParam)) {
52         return ERROR;
53     }
54     if (!IsValidPermissionType(permissionTypeParam)) {
55         return ERROR;
56     }
57     // parse fileId
58     int fileId = -1;
59     if (!GetIntFromValuesBucket(cmd.GetValueBucket(), AppUriPermissionColumn::FILE_ID, fileId)) {
60         return ERROR;
61     }
62     if (!IsPhotoExist(fileId)) {
63         return ERROR;
64     }
65     // query permission data before insert
66     int queryFlag = ERROR;
67     shared_ptr<ResultSet> resultSet = QueryNewData(cmd.GetValueBucket(), queryFlag);
68     // Update the permissionType
69     if (queryFlag > 0) {
70         return UpdatePermissionType(resultSet, permissionTypeParam);
71     }
72     if (queryFlag < 0) {
73         return ERROR;
74     }
75 
76     // delete the temporary permission when the app dies
77     if (AppUriPermissionColumn::PERMISSION_TYPES_TEMPORARY.find(permissionTypeParam) !=
78         AppUriPermissionColumn::PERMISSION_TYPES_TEMPORARY.end()) {
79         MedialibraryAppStateObserverManager::GetInstance().SubscribeAppState();
80     }
81 
82     auto rdbStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
83     if (rdbStore == nullptr) {
84         MEDIA_ERR_LOG("get rdbStore error");
85         return ERROR;
86     }
87     // insert data
88     int64_t outRowId = -1;
89     cmd.GetValueBucket().PutLong(AppUriPermissionColumn::DATE_MODIFIED,
90         MediaFileUtils::UTCTimeMilliSeconds());
91 
92     cmd.GetValueBucket().Delete(AppUriSensitiveColumn::HIDE_SENSITIVE_TYPE);
93     cmd.GetValueBucket().Delete(AppUriSensitiveColumn::IS_FORCE_SENSITIVE);
94     cmd.SetTableName(AppUriPermissionColumn::APP_URI_PERMISSION_TABLE);
95 
96     int32_t errCode = rdbStore->Insert(cmd, outRowId);
97     if (errCode != NativeRdb::E_OK) {
98         MEDIA_ERR_LOG("insert into db error, errCode=%{public}d", errCode);
99         return ERROR;
100     }
101     MEDIA_INFO_LOG("insert appUriPermission ok");
102     return SUCCEED;
103 }
104 
BatchInsert(MediaLibraryCommand & cmd,const std::vector<DataShare::DataShareValuesBucket> & values)105 int32_t MediaLibraryAppUriPermissionOperations::BatchInsert(
106     MediaLibraryCommand &cmd, const std::vector<DataShare::DataShareValuesBucket> &values)
107 {
108     MEDIA_INFO_LOG("batch insert begin");
109 
110     if (!IsPhotosAllExist(values)) {
111         return ERROR;
112     }
113     std::shared_ptr<TransactionOperations> trans = make_shared<TransactionOperations>(__func__);
114     std::function<int(void)> func = [&]()->int {
115         return BatchInsertInner(cmd, values, trans);
116     };
117     int32_t errCode = trans->RetryTrans(func);
118     if (errCode != E_OK) {
119         MEDIA_ERR_LOG("BatchInsert: trans retry fail!, ret:%{public}d", errCode);
120         return errCode;
121     }
122     MEDIA_INFO_LOG("batch insert ok");
123     return SUCCEED;
124 }
125 
BatchInsertInner(MediaLibraryCommand & cmd,const std::vector<DataShare::DataShareValuesBucket> & values,std::shared_ptr<TransactionOperations> trans)126 int32_t MediaLibraryAppUriPermissionOperations::BatchInsertInner(
127     MediaLibraryCommand &cmd, const std::vector<DataShare::DataShareValuesBucket> &values,
128     std::shared_ptr<TransactionOperations> trans)
129 {
130     int32_t errCode = NativeRdb::E_OK;
131     std::vector<ValuesBucket> insertVector;
132     for (auto it = values.begin(); it != values.end(); it++) {
133         ValuesBucket value = RdbUtils::ToValuesBucket(*it);
134         int queryFlag = -1;
135         std::shared_ptr<OHOS::NativeRdb::ResultSet> resultSet = QueryNewData(value, queryFlag);
136         if (queryFlag < 0) {
137             return ERROR;
138         }
139         // permissionType from param
140         int permissionTypeParam = -1;
141         if (!GetIntFromValuesBucket(value, AppUriPermissionColumn::PERMISSION_TYPE,
142             permissionTypeParam)) {
143             return ERROR;
144         }
145 
146         value.Delete(AppUriSensitiveColumn::HIDE_SENSITIVE_TYPE);
147         value.Delete(AppUriSensitiveColumn::IS_FORCE_SENSITIVE);
148 
149         if (queryFlag == 0) {
150             // delete the temporary permission when the app dies
151             if (AppUriPermissionColumn::PERMISSION_TYPES_TEMPORARY.find(permissionTypeParam) !=
152                 AppUriPermissionColumn::PERMISSION_TYPES_TEMPORARY.end()) {
153                 MedialibraryAppStateObserverManager::GetInstance().SubscribeAppState();
154             }
155             value.PutLong(AppUriPermissionColumn::DATE_MODIFIED, MediaFileUtils::UTCTimeMilliSeconds());
156             insertVector.push_back(value);
157         } else if (UpdatePermissionType(resultSet, permissionTypeParam) == ERROR) {
158             return ERROR;
159         }
160     }
161 
162     if (!insertVector.empty()) {
163         if (errCode != E_OK) {
164             MEDIA_ERR_LOG("start transaction error, errCode = %{public}d", errCode);
165             return ERROR;
166         }
167         int64_t outRowId = -1;
168         errCode = trans->BatchInsert(outRowId, AppUriPermissionColumn::APP_URI_PERMISSION_TABLE, insertVector);
169         if (errCode != NativeRdb::E_OK) {
170             MEDIA_ERR_LOG("batch insert err=%{public}d", errCode);
171             return ERROR;
172         }
173     }
174     return errCode;
175 }
176 
DeleteOperation(NativeRdb::RdbPredicates & predicates)177 int32_t MediaLibraryAppUriPermissionOperations::DeleteOperation(NativeRdb::RdbPredicates &predicates)
178 {
179     MEDIA_INFO_LOG("delete begin");
180     int deleteRow = MediaLibraryRdbStore::Delete(predicates);
181     MEDIA_INFO_LOG("deleted row=%{public}d", deleteRow);
182     return deleteRow < 0 ? ERROR : SUCCEED;
183 }
184 
QueryOperation(DataShare::DataSharePredicates & predicates,std::vector<std::string> & fetchColumns)185 std::shared_ptr<OHOS::NativeRdb::ResultSet> MediaLibraryAppUriPermissionOperations::QueryOperation(
186     DataShare::DataSharePredicates &predicates, std::vector<std::string> &fetchColumns)
187 {
188     RdbPredicates rdbPredicates = RdbUtils::ToPredicates(predicates,
189         AppUriPermissionColumn::APP_URI_PERMISSION_TABLE);
190     std::shared_ptr<OHOS::NativeRdb::ResultSet> resultSet =
191         MediaLibraryRdbStore::QueryWithFilter(rdbPredicates, fetchColumns);
192     if (resultSet == nullptr) {
193         return nullptr;
194     }
195     int32_t numRows = 0;
196     resultSet->GetRowCount(numRows);
197     if (numRows == 0) {
198         return nullptr;
199     }
200     resultSet->GoToFirstRow();
201     return resultSet;
202 }
203 
QueryNewData(OHOS::NativeRdb::ValuesBucket & valueBucket,int & resultFlag)204 std::shared_ptr<OHOS::NativeRdb::ResultSet> MediaLibraryAppUriPermissionOperations::QueryNewData(
205     OHOS::NativeRdb::ValuesBucket &valueBucket, int &resultFlag)
206 {
207     // parse tokenId
208     int64_t srcTokenId;
209     ValueObject valueObject;
210     if (valueBucket.GetObject(AppUriPermissionColumn::SOURCE_TOKENID, valueObject)) {
211         valueObject.GetLong(srcTokenId);
212     }
213     int64_t destTokenId;
214     if (valueBucket.GetObject(AppUriPermissionColumn::TARGET_TOKENID, valueObject)) {
215         valueObject.GetLong(destTokenId);
216     }
217     // parse fileId
218     int fileId = -1;
219     if (!GetIntFromValuesBucket(valueBucket, AppUriPermissionColumn::FILE_ID, fileId)) {
220         resultFlag = ERROR;
221         return nullptr;
222     }
223 
224     // parse uriType
225     int uriType = -1;
226     if (!GetIntFromValuesBucket(valueBucket, AppUriPermissionColumn::URI_TYPE, uriType)) {
227         resultFlag = ERROR;
228         return nullptr;
229     }
230 
231     OHOS::DataShare::DataSharePredicates permissionPredicates;
232     permissionPredicates.And()->EqualTo(AppUriPermissionColumn::FILE_ID, fileId);
233     permissionPredicates.And()->EqualTo(AppUriPermissionColumn::URI_TYPE, uriType);
234     permissionPredicates.And()->EqualTo(AppUriPermissionColumn::SOURCE_TOKENID, srcTokenId);
235     permissionPredicates.And()->EqualTo(AppUriPermissionColumn::TARGET_TOKENID, destTokenId);
236 
237     vector<string> fetchColumns;
238     fetchColumns.push_back(AppUriPermissionColumn::ID);
239     fetchColumns.push_back(AppUriPermissionColumn::PERMISSION_TYPE);
240 
241     shared_ptr<ResultSet> resultSet = QueryOperation(permissionPredicates, fetchColumns);
242     resultFlag = (resultSet == nullptr ? NO_DATA_EXIST : ALREADY_EXIST);
243     return resultSet;
244 }
245 
GetIntFromValuesBucket(OHOS::NativeRdb::ValuesBucket & valueBucket,const std::string & column,int & result)246 bool MediaLibraryAppUriPermissionOperations::GetIntFromValuesBucket(
247     OHOS::NativeRdb::ValuesBucket &valueBucket, const std::string &column, int &result)
248 {
249     ValueObject valueObject;
250     bool ret = valueBucket.GetObject(column, valueObject);
251     if (!ret) {
252         MEDIA_ERR_LOG("valueBucket param without %{public}s", column.c_str());
253         return false;
254     }
255     result = valueObject;
256     return true;
257 }
258 
UpdatePermissionType(shared_ptr<ResultSet> & resultSetDB,int & permissionTypeParam,std::shared_ptr<TransactionOperations> trans)259 int MediaLibraryAppUriPermissionOperations::UpdatePermissionType(shared_ptr<ResultSet> &resultSetDB,
260     int &permissionTypeParam, std::shared_ptr<TransactionOperations> trans)
261 {
262     int32_t permissionTypeDB =
263         MediaLibraryRdbStore::GetInt(resultSetDB, AppUriPermissionColumn::PERMISSION_TYPE);
264     if (!CanOverride(permissionTypeParam, permissionTypeDB)) {
265         return ALREADY_EXIST;
266     }
267 
268     // delete the temporary permission when the app dies
269     if (AppUriPermissionColumn::PERMISSION_TYPES_TEMPORARY.find(permissionTypeParam) !=
270         AppUriPermissionColumn::PERMISSION_TYPES_TEMPORARY.end()) {
271         MedialibraryAppStateObserverManager::GetInstance().SubscribeAppState();
272     }
273 
274     // update permission type
275     ValuesBucket updateVB;
276     updateVB.PutInt(AppUriPermissionColumn::PERMISSION_TYPE, permissionTypeParam);
277     updateVB.PutLong(AppUriPermissionColumn::DATE_MODIFIED, MediaFileUtils::UTCTimeMilliSeconds());
278     int32_t idDB = MediaLibraryRdbStore::GetInt(resultSetDB, AppUriPermissionColumn::ID);
279 
280     RdbPredicates updateRdbPredicates(AppUriPermissionColumn::APP_URI_PERMISSION_TABLE);
281     updateRdbPredicates.EqualTo(AppUriPermissionColumn::ID, idDB);
282     int32_t updateRows = 0;
283     if (trans == nullptr) {
284         updateRows = MediaLibraryRdbStore::UpdateWithDateTime(updateVB, updateRdbPredicates);
285     } else {
286         updateRows = trans->Update(updateVB, updateRdbPredicates);
287     }
288     if (updateRows < 1) {
289         MEDIA_ERR_LOG("upgrade permissionType error,idDB=%{public}d", idDB);
290         return ERROR;
291     }
292     MEDIA_INFO_LOG("update ok,Rows=%{public}d", updateRows);
293     return SUCCEED;
294 }
295 
IsValidPermissionType(int & permissionType)296 bool MediaLibraryAppUriPermissionOperations::IsValidPermissionType(int &permissionType)
297 {
298     bool isValid = AppUriPermissionColumn::PERMISSION_TYPES_ALL.find(permissionType)
299         != AppUriPermissionColumn::PERMISSION_TYPES_ALL.end();
300     if (!isValid) {
301         MEDIA_ERR_LOG("invalid permissionType=%{public}d", permissionType);
302     }
303     return isValid;
304 }
305 
CanOverride(int & permissionTypeParam,int & permissionTypeDB)306 bool MediaLibraryAppUriPermissionOperations::CanOverride(int &permissionTypeParam, int &permissionTypeDB)
307 {
308     MEDIA_INFO_LOG("permissionTypeParam=%{public}d,permissionTypeDB=%{public}d",
309         permissionTypeParam, permissionTypeDB);
310     // Equal permissions do not need to be overridden
311     if (permissionTypeParam == permissionTypeDB) {
312         return false;
313     }
314     // temporary permission can't override persist permission
315     if (AppUriPermissionColumn::PERMISSION_TYPES_TEMPORARY.find(permissionTypeParam) !=
316         AppUriPermissionColumn::PERMISSION_TYPES_TEMPORARY.end()
317         && AppUriPermissionColumn::PERMISSION_TYPES_PERSIST.find(permissionTypeDB) !=
318         AppUriPermissionColumn::PERMISSION_TYPES_PERSIST.end()
319     ) {
320         return false;
321     }
322     // persist permission can override temporary permission
323     if (AppUriPermissionColumn::PERMISSION_TYPES_TEMPORARY.find(permissionTypeDB) !=
324         AppUriPermissionColumn::PERMISSION_TYPES_TEMPORARY.end()
325         && AppUriPermissionColumn::PERMISSION_TYPES_PERSIST.find(permissionTypeParam) !=
326         AppUriPermissionColumn::PERMISSION_TYPES_PERSIST.end()
327     ) {
328         return true;
329     }
330     // Temporary permissions can override each other.
331     if (AppUriPermissionColumn::PERMISSION_TYPES_TEMPORARY.find(permissionTypeParam) !=
332         AppUriPermissionColumn::PERMISSION_TYPES_TEMPORARY.end()
333         && AppUriPermissionColumn::PERMISSION_TYPES_TEMPORARY.find(permissionTypeDB) !=
334         AppUriPermissionColumn::PERMISSION_TYPES_PERSIST.end()
335     ) {
336         return true;
337     }
338     // PERMISSION_PERSIST_READ_WRITE can override PERMISSION_PERSIST_READ, but not vice verse.
339     return permissionTypeParam == AppUriPermissionColumn::PERMISSION_PERSIST_READ_WRITE;
340 }
341 
IsPhotoExist(int32_t & photoFileId)342 bool MediaLibraryAppUriPermissionOperations::IsPhotoExist(int32_t &photoFileId)
343 {
344     // query whether photo exists.
345     RdbPredicates rdbPredicates(PhotoColumn::PHOTOS_TABLE);
346     rdbPredicates.And()->EqualTo(PhotoColumn::MEDIA_ID, std::to_string(photoFileId));
347     vector<string> photoColumns;
348     photoColumns.push_back(PhotoColumn::MEDIA_ID);
349     shared_ptr<NativeRdb::ResultSet> photoRestultSet =
350         MediaLibraryRdbStore::QueryWithFilter(rdbPredicates, photoColumns);
351     if (photoRestultSet == nullptr) {
352         MEDIA_ERR_LOG("query photoRestultSet is null,fileId=%{public}d", photoFileId);
353         return false;
354     }
355     int32_t photoNumRows = 0;
356     photoRestultSet->GetRowCount(photoNumRows);
357     if (photoNumRows == 0) {
358         MEDIA_ERR_LOG("query photo not exist,fileId=%{public}d", photoFileId);
359         return false;
360     }
361     return true;
362 }
363 
IsPhotosAllExist(const std::vector<DataShare::DataShareValuesBucket> & values)364 bool MediaLibraryAppUriPermissionOperations::IsPhotosAllExist(
365     const std::vector<DataShare::DataShareValuesBucket> &values)
366 {
367     std::vector<std::string> fileIds;
368     bool isValid = false;
369     for (auto it = values.begin(); it != values.end(); it++) {
370         int fileId = it->Get(AppUriPermissionColumn::FILE_ID, isValid);
371         if (!isValid) {
372             MEDIA_ERR_LOG("get fileId error");
373             return false;
374         }
375         fileIds.push_back(std::to_string(static_cast<int32_t>(fileId)));
376     }
377     // query whether photos exists.
378     RdbPredicates rdbPredicates(PhotoColumn::PHOTOS_TABLE);
379     rdbPredicates.And()->In(MediaColumn::MEDIA_ID, fileIds);
380     vector<string> photoColumns;
381     photoColumns.push_back(PhotoColumn::MEDIA_ID);
382     shared_ptr<NativeRdb::ResultSet> photoRestultSet =
383         MediaLibraryRdbStore::QueryWithFilter(rdbPredicates, photoColumns);
384     if (photoRestultSet == nullptr) {
385         MEDIA_ERR_LOG("query photoRestultSet is null");
386         return false;
387     }
388     int32_t photoNumRows = 0;
389     photoRestultSet->GetRowCount(photoNumRows);
390     size_t photoNum = static_cast<size_t>(photoNumRows);
391     if (photoNum != fileIds.size()) {
392         MEDIA_ERR_LOG("some photo not exist");
393         return false;
394     }
395     return true;
396 }
397 
398 } // namespace Media
399 } // namespace OHOS