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