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