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