• 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 
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