diff --git a/interfaces/innerkits/privacy/test/unittest/src/privacy_kit_test.cpp b/interfaces/innerkits/privacy/test/unittest/src/privacy_kit_test.cpp index 4c5b9de0288e90d9b8a081c8670d51cb127fce48..59e2e53d03c2c715b8d9a8e51f12209495247695 100644 --- a/interfaces/innerkits/privacy/test/unittest/src/privacy_kit_test.cpp +++ b/interfaces/innerkits/privacy/test/unittest/src/privacy_kit_test.cpp @@ -132,6 +132,52 @@ void PrivacyKitTest::CheckPermissionUsedResult(const PermissionUsedRequest& requ ASSERT_EQ(totalSuccessCount, successCount); ASSERT_EQ(totalFailCount, failCount); } +namespace OHOS { +namespace Security { +namespace AccessToken { +namespace { + void SetTokenID(std::vector& g_InfoParms_List, + std::vector& g_TokenId_List, int32_t number) + { + SetSelfTokenID(g_selfTokenId); + for (int32_t i = 0; i < number; i++) { + HapInfoParams g_InfoParmsTmp = { + .userID = i, + .bundleName = "ohos.privacy_test.bundle" + std::to_string(i), + .instIndex = i, + .appIDDesc = "privacy_test.bundle" + std::to_string(i) + }; + g_InfoParms_List.push_back(g_InfoParmsTmp); + HapPolicyParams g_PolicyPramsTmp = { + .apl = APL_NORMAL, + .domain = "test.domain." + std::to_string(i) + }; + AccessTokenKit::AllocHapToken(g_InfoParmsTmp, g_PolicyPramsTmp); + AccessTokenID g_TokenId_Tmp = AccessTokenKit::GetHapTokenID(g_InfoParmsTmp.userID, + g_InfoParmsTmp.bundleName, + g_InfoParmsTmp.instIndex); + g_TokenId_List.push_back(g_TokenId_Tmp); + } + AccessTokenID tokenId = AccessTokenKit::GetHapTokenID(100, "com.ohos.permissionmanager", 0); + SetSelfTokenID(tokenId); + } + + void DeleteTokenID(std::vector& g_InfoParms_List) + { + SetSelfTokenID(g_selfTokenId); + for (size_t i = 0; i < g_InfoParms_List.size(); i++) { + AccessTokenID g_TokenId_Tmp = AccessTokenKit::GetHapTokenID(g_InfoParms_List[i].userID, + g_InfoParms_List[i].bundleName, + g_InfoParms_List[i].instIndex); + AccessTokenKit::DeleteToken(g_TokenId_Tmp); + } + AccessTokenID tokenId = AccessTokenKit::GetHapTokenID(100, "com.ohos.permissionmanager", 0); + SetSelfTokenID(tokenId); + } +} +} // namespace AccessToken +} // namespace Security +} // namespace OHOS /** * @tc.name: AddPermissionUsedRecord001 @@ -536,4 +582,84 @@ HWTEST_F(PrivacyKitTest, GetPermissionUsedRecordsAsync002, TestSize.Level1) BuildQueryRequest(g_TokenId_A, GetLocalDeviceUdid(), "", permissionList, request); OHOS::sptr callback(new TestCallBack()); ASSERT_EQ(RET_NO_ERROR, PrivacyKit::GetPermissionUsedRecords(request, callback)); +} + +/** + * @tc.name: AddPermissionUsedRecord007 + * @tc.desc: AddPermissionUsedRecord merge more than 10 records + * @tc.type: FUNC + * @tc.require:Issue Number + */ +HWTEST_F(PrivacyKitTest, AddPermissionUsedRecord007, TestSize.Level1) +{ + std::vector addPermissionList = { + "ohos.permission.ANSWER_CALL", + "ohos.permission.READ_CALENDAR", + "ohos.permission.WRITE_CALENDAR", + "ohos.permission.SEND_MESSAGES", + "ohos.permission.WRITE_CALL_LOG", + "ohos.permission.READ_CALL_LOG", + "ohos.permission.READ_CELL_MESSAGES", + "ohos.permission.MICROPHONE", + "ohos.permission.RECEIVE_WAP_MESSAGES", + "ohos.permission.RECEIVE_SMS", + "ohos.permission.RECEIVE_MMS" + }; + for (int32_t i = 0; i < 10; i++) { + ASSERT_EQ(RET_NO_ERROR, PrivacyKit::AddPermissionUsedRecord(g_TokenId_A, addPermissionList[i], 1, 0)); + } + PermissionUsedRequest request; + PermissionUsedResult result; + std::vector permissionList; + BuildQueryRequest(g_TokenId_A, GetLocalDeviceUdid(), g_InfoParmsA.bundleName, permissionList, request); + request.flag = FLAG_PERMISSION_USAGE_DETAIL; + ASSERT_EQ(RET_NO_ERROR, PrivacyKit::GetPermissionUsedRecords(request, result)); + ASSERT_EQ(1, result.bundleRecords.size()); + CheckPermissionUsedResult(request, result, 10, 10, 0); + + ASSERT_EQ(RET_NO_ERROR, PrivacyKit::AddPermissionUsedRecord(g_TokenId_A, addPermissionList[10], 1, 0)); + ASSERT_EQ(RET_NO_ERROR, PrivacyKit::GetPermissionUsedRecords(request, result)); + ASSERT_EQ(1, result.bundleRecords.size()); + ASSERT_EQ(10, result.bundleRecords[0].permissionRecords.size()); + ASSERT_EQ(1, result.bundleRecords[0].permissionRecords[0].accessRecords.size()); + CheckPermissionUsedResult(request, result, 10, 10, 0); +} + +/** + * @tc.name: AddPermissionUsedRecord008 + * @tc.desc: AddPermissionUsedRecord user_grant permission. + * @tc.type: FUNC + * @tc.require:Issue Number + */ +HWTEST_F(PrivacyKitTest, AddPermissionUsedRecord008, TestSize.Level1) +{ + std::vector g_InfoParms_List; + std::vector g_TokenId_List; + SetTokenID(g_InfoParms_List, g_TokenId_List, 100); + std::vector addPermissionList = { + "ohos.permission.ANSWER_CALL", + "ohos.permission.READ_CALENDAR", + "ohos.permission.WRITE_CALENDAR", + "ohos.permission.SEND_MESSAGES", + "ohos.permission.WRITE_CALL_LOG" + }; + for (int32_t i = 0; i < 500; i++) { + ASSERT_EQ(RET_NO_ERROR, PrivacyKit::AddPermissionUsedRecord(g_TokenId_List[i % 100], + addPermissionList[i % 5], 1, 0)); + } + sleep(100); + for (int32_t i = 0; i < 100; i++) { + PermissionUsedRequest request; + PermissionUsedResult result; + std::vector permissionList; + BuildQueryRequest(g_TokenId_List[i], GetLocalDeviceUdid(), + g_InfoParms_List[i].bundleName, permissionList, request); + request.flag = FLAG_PERMISSION_USAGE_DETAIL; + ASSERT_EQ(RET_NO_ERROR, PrivacyKit::GetPermissionUsedRecords(request, result)); + ASSERT_EQ(1, result.bundleRecords.size()); + ASSERT_EQ(1, result.bundleRecords[0].permissionRecords.size()); + ASSERT_EQ(1, result.bundleRecords[0].permissionRecords[0].accessRecords.size()); + CheckPermissionUsedResult(request, result, 1, 5, 0); + } + DeleteTokenID(g_InfoParms_List); } \ No newline at end of file diff --git a/services/privacymanager/BUILD.gn b/services/privacymanager/BUILD.gn index 5a98012890bd6944f6f56f046038ce0e0e432b02..dc8a0a691874e3dd2d790caaac462e5642048ff8 100644 --- a/services/privacymanager/BUILD.gn +++ b/services/privacymanager/BUILD.gn @@ -35,6 +35,8 @@ ohos_shared_library("privacy_manager_service") { "//base/security/access_token/interfaces/innerkits/privacy/include", "//base/security/access_token/services/common/database/include", "//third_party/json/include", + "//third_party/googletest/include", + "//utils/native/base/include", ] sources = [ @@ -48,6 +50,7 @@ ohos_shared_library("privacy_manager_service") { "src/record/permission_record.cpp", "src/record/permission_record_manager.cpp", "src/record/permission_record_repository.cpp", + "src/record/permission_used_record_cache.cpp", "src/record/permission_visitor.cpp", "src/record/permission_visitor_repository.cpp", "src/service/privacy_manager_service.cpp", diff --git a/services/privacymanager/include/database/permission_used_record_db.h b/services/privacymanager/include/database/permission_used_record_db.h index 059e0082aac7277038e93678e9b64272f580eb33..f362f958226d6dc2a74eb18ec6f72608638e6c20 100644 --- a/services/privacymanager/include/database/permission_used_record_db.h +++ b/services/privacymanager/include/database/permission_used_record_db.h @@ -48,7 +48,9 @@ public: const GenericValues& orConditions, std::vector& results); int32_t Modify(const DataType type, const GenericValues& modifyValues, const GenericValues& conditions); int32_t RefreshAll(const DataType type, const std::vector& values); - + int32_t Count(const DataType type, GenericValues& result); + int32_t DeleteExpireRecords(const DataType type, const GenericValues& andConditions); + int32_t DeleteExcessiveRecords(const DataType type, int32_t excessiveSize); void OnCreate() override; void OnUpdate() override; @@ -70,6 +72,10 @@ private: const std::vector& andColumns, const std::vector& orColumns) const; std::string CreateUpdatePrepareSqlCmd(const DataType type, const std::vector& modifyColumns, const std::vector& conditionColumns) const; + std::string CreateCountPrepareSqlCmd(const DataType type) const; + std::string CreateDeleteExpireRecordsPrepareSqlCmd(const DataType type, + const std::vector& andColumns) const; + std::string CreateDeleteExcessiveRecordsPrepareSqlCmd(const DataType type, int32_t excessiveSize) const; private: inline static const std::string PERMISSION_VISITOR_TABLE = "permission_visitor_table"; diff --git a/services/privacymanager/include/record/permission_record_manager.h b/services/privacymanager/include/record/permission_record_manager.h index 727599d119badad5f773cf53de783e45b9cf33d6..187b7237f8fccb94a6e19532b6a1dbf9f580c4a7 100644 --- a/services/privacymanager/include/record/permission_record_manager.h +++ b/services/privacymanager/include/record/permission_record_manager.h @@ -46,6 +46,7 @@ public: int32_t GetPermissionUsedRecordsAsync( const PermissionUsedRequest& request, const sptr& callback); std::string DumpRecordInfo(const std::string& bundleName, const std::string& permissionName); + void ExecuteReadRecordBufferTask(); private: PermissionRecordManager(); @@ -59,6 +60,8 @@ private: void ExecuteDeletePermissionRecordTask(); int32_t DeletePermissionRecord(int32_t days); + + void ReadRecordBufferToDB(); bool GetRecordsFromDB(const PermissionUsedRequest& request, PermissionUsedResult& result); bool GetRecords(int32_t flag, std::vector recordValues, BundleUsedRecord& bundleRecord, PermissionUsedResult& result); @@ -67,6 +70,7 @@ private: bool IsLocalDevice(const std::string& deviceId); OHOS::ThreadPool deleteTaskWorker_; + OHOS::ThreadPool readRecordBufferTaskWorker_; bool hasInited_; OHOS::Utils::RWLock rwLock_; }; diff --git a/services/privacymanager/include/record/permission_record_repository.h b/services/privacymanager/include/record/permission_record_repository.h index ffda94fb527f1ed4164f39216d641c3ff16bbaa9..eb69fcf173b749f1f4dc9ecd3fabf1c576f823c4 100644 --- a/services/privacymanager/include/record/permission_record_repository.h +++ b/services/privacymanager/include/record/permission_record_repository.h @@ -33,6 +33,10 @@ public: bool FindRecordValues(const GenericValues& andConditionValues, const GenericValues& orConditionValues, std::vector& recordValues); bool RemoveRecordValues(const GenericValues& conditionValues); + + int32_t CountRecordValues(GenericValues& resultValues); + bool DeleteExpireRecordsValues(const GenericValues& andConditions); + bool DeleteExcessiveSizeRecordValues(int32_t excessiveSize); }; } // namespace AccessToken } // namespace Security diff --git a/services/privacymanager/include/record/permission_used_record_cache.h b/services/privacymanager/include/record/permission_used_record_cache.h new file mode 100644 index 0000000000000000000000000000000000000000..f833ffe8652f4c20845c660c0e5d9fb7bd592b39 --- /dev/null +++ b/services/privacymanager/include/record/permission_used_record_cache.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef PERMISSION_USED_RECORD_CACHE_H +#define PERMISSION_USED_RECORD_CACHE_H + +#include +#include +#include +#include "nocopyable.h" +#include "permission_record.h" +#include "rwlock.h" +namespace OHOS { +namespace Security { +namespace AccessToken { +class PermissionUsedRecordCache { +public: + static PermissionUsedRecordCache& GetInstance(); + + int32_t AddVisitorRecord(PermissionRecord& record); + void GetVisitorRecord(int32_t visitor, std::vector& findRecordsValues); + void GetVisitorRecord(int32_t visitor, const std::vector& permissionList, + std::vector& findRecordsValues); + int32_t RemoveVisitorRecord(int32_t visitorId); + int32_t GetDeleteVisitorRecord(int32_t visitorId, std::vector& deleteVisitorRecord); + void WriteVisitorRecordBuffer(PermissionRecord& record, bool isExisted); + void ReadVisitorRecordBuffer(); + bool WriteRecordsToDB(); + void ClearVisitorRecord(); + int32_t GetReadableSize(); + +private: + static int32_t readableSize; + static int32_t writePos; + static int32_t readPos; + static std::vector recordBuffer; + static std::vector writeToDbBuffer; + static std::map> visitorRecord; + OHOS::Utils::RWLock cacheLock_; + const static int32_t MAX_RECORD_BUFFER_SIZE = 500; + const static int32_t MAX_RECORD_SIZE = 10; + + enum resetType { + OVERWRITE = -1, + WRITEDBFAILED = 0, + }; +}; +} // namespace AccessToken +} // namespace Security +} // namespace OHOS +#endif // PERMISSION_USED_RECORD_CACHE_H diff --git a/services/privacymanager/src/database/permission_used_record_db.cpp b/services/privacymanager/src/database/permission_used_record_db.cpp index 60b82be4b1912f29cf22533fb71733ab3e29d17c..805df586e403854f1343903874923cb598e4a4c5 100644 --- a/services/privacymanager/src/database/permission_used_record_db.cpp +++ b/services/privacymanager/src/database/permission_used_record_db.cpp @@ -224,6 +224,51 @@ int32_t PermissionUsedRecordDb::RefreshAll(const DataType type, const std::vecto CommitTransaction(); return SUCCESS; } +int32_t PermissionUsedRecordDb::Count(const DataType type, GenericValues& result) +{ + OHOS::Utils::UniqueWriteGuard lock(this->rwLock_); + std::string countSql = CreateCountPrepareSqlCmd(type); + auto countStatement = Prepare(countSql); + int32_t ret = countStatement.Step(); + if (ret == Statement::State::ROW) { + int32_t column = 0; + result.Put("COUNT", countStatement.GetValue(column, true)); + } + return SUCCESS; +} + +int32_t PermissionUsedRecordDb::DeleteExpireRecords(const DataType type, + const GenericValues& andConditions) +{ + OHOS::Utils::UniqueWriteGuard lock(this->rwLock_); + std::vector andColumns = andConditions.GetAllKeys(); + if (andColumns.size() != 0) { + std::string deleteExpireSql = CreateDeleteExpireRecordsPrepareSqlCmd(type, andColumns); + auto deleteExpireStatement = Prepare(deleteExpireSql); + for (const auto& columnName : andColumns) { + deleteExpireStatement.Bind(columnName, andConditions.Get(columnName)); + } + int32_t ret = deleteExpireStatement.Step(); + if (ret != Statement::State::DONE) { + return FAILURE; + } + } + return SUCCESS; +} + +int32_t PermissionUsedRecordDb::DeleteExcessiveRecords(const DataType type, int32_t excessiveSize) +{ + OHOS::Utils::UniqueWriteGuard lock(this->rwLock_); + if (excessiveSize > 0) { + std::string deleteExcessiveSql = CreateDeleteExcessiveRecordsPrepareSqlCmd(type, excessiveSize); + auto deleteExcessiveStatement = Prepare(deleteExcessiveSql); + int32_t ret = deleteExcessiveStatement.Step(); + if (ret != Statement::State::DONE) { + return FAILURE; + } + } + return SUCCESS; +} std::string PermissionUsedRecordDb::CreateInsertPrepareSqlCmd(const DataType type) const { @@ -335,6 +380,58 @@ std::string PermissionUsedRecordDb::CreateSelectByConditionPrepareSqlCmd(const D return sql; } +std::string PermissionUsedRecordDb::CreateCountPrepareSqlCmd(const DataType type) const +{ + auto it = dataTypeToSqlTable_.find(type); + if (it == dataTypeToSqlTable_.end()) { + return std::string(); + } + std::string sql = "select count(*) from " + it->second.tableName_; + return sql; +} + +std::string PermissionUsedRecordDb::CreateDeleteExpireRecordsPrepareSqlCmd(const DataType type, + const std::vector& andColumns) const +{ + auto it = dataTypeToSqlTable_.find(type); + if (it == dataTypeToSqlTable_.end()) { + return std::string(); + } + std::string sql = "delete from " + it->second.tableName_ + " where "; + sql.append(FIELD_TIMESTAMP + " in (select "); + sql.append(FIELD_TIMESTAMP + " from " + it->second.tableName_ + " where 1 = 1"); + for (const auto& andColName : andColumns) { + if (andColName == FIELD_TIMESTAMP_BEGIN) { + sql.append(" and "); + sql.append(FIELD_TIMESTAMP + " >=:" + andColName); + } else if (andColName == FIELD_TIMESTAMP_END) { + sql.append(" and "); + sql.append(FIELD_TIMESTAMP + " <=:" + andColName); + } else { + sql.append(" and "); + sql.append(andColName + "=:" + andColName); + } + } + sql.append(" )"); + return sql; +} + +std::string PermissionUsedRecordDb::CreateDeleteExcessiveRecordsPrepareSqlCmd(const DataType type, + int32_t excessiveSize) const +{ + auto it = dataTypeToSqlTable_.find(type); + if (it == dataTypeToSqlTable_.end()) { + return std::string(); + } + std::string sql = "delete from " + it->second.tableName_ + " where "; + sql.append(FIELD_TIMESTAMP + " in (select "); + sql.append(FIELD_TIMESTAMP + " from " + it->second.tableName_ + " order by "); + sql.append(FIELD_TIMESTAMP + " limit "); + sql.append(std::to_string(excessiveSize) + " )"); + return sql; +} + + int32_t PermissionUsedRecordDb::CreatePermissionVisitorTable() const { auto it = dataTypeToSqlTable_.find(DataType::PERMISSION_VISITOR); diff --git a/services/privacymanager/src/record/permission_record_manager.cpp b/services/privacymanager/src/record/permission_record_manager.cpp index 024790c7d1f230b01a13fe4c1ca016359d66253c..6f0c022ca5238e1f96ba91c21c1740747328be59 100644 --- a/services/privacymanager/src/record/permission_record_manager.cpp +++ b/services/privacymanager/src/record/permission_record_manager.cpp @@ -14,7 +14,7 @@ */ #include "permission_record_manager.h" - +#include #include "accesstoken_kit.h" #include "accesstoken_log.h" #include "constant.h" @@ -22,6 +22,7 @@ #include "data_translator.h" #include "field_const.h" #include "permission_record_repository.h" +#include "permission_used_record_cache.h" #include "permission_visitor_repository.h" #include "time_util.h" #include "to_string.h" @@ -105,50 +106,8 @@ bool PermissionRecordManager::AddRecord( if (!GetPermissionsRecord(visitorId, permissionName, successCount, failCount, record)) { return false; } - - GenericValues nullValues; - GenericValues recordValues; - std::vector insertValues; - std::vector findValues; - PermissionRecord::TranslationIntoGenericValues(record, recordValues); - - int64_t insertTimestamp = record.timestamp; - int64_t insertAccessDuration = record.accessDuration; - int32_t insertAccessCount = record.accessCount; - int32_t insertRejectCount = record.rejectCount; - recordValues.Remove(FIELD_TIMESTAMP); - recordValues.Remove(FIELD_ACCESS_DURATION); - recordValues.Remove(FIELD_ACCESS_COUNT); - recordValues.Remove(FIELD_REJECT_COUNT); - if (!PermissionRecordRepository::GetInstance().FindRecordValues(recordValues, nullValues, findValues)) { - return false; - } - - recordValues.Put(FIELD_TIMESTAMP, insertTimestamp); - recordValues.Put(FIELD_ACCESS_DURATION, insertAccessDuration); - recordValues.Put(FIELD_ACCESS_COUNT, insertAccessCount); - recordValues.Put(FIELD_REJECT_COUNT, insertRejectCount); - for (const auto& rec : findValues) { - if (insertTimestamp - rec.GetInt64(FIELD_TIMESTAMP) < Constant::PRECISE) { - insertAccessDuration += rec.GetInt64(FIELD_ACCESS_DURATION); - insertAccessCount += rec.GetInt(FIELD_ACCESS_COUNT); - insertRejectCount += rec.GetInt(FIELD_REJECT_COUNT); - recordValues.Remove(FIELD_ACCESS_DURATION); - recordValues.Remove(FIELD_ACCESS_COUNT); - recordValues.Remove(FIELD_REJECT_COUNT); - - recordValues.Put(FIELD_ACCESS_DURATION, insertAccessDuration); - recordValues.Put(FIELD_ACCESS_COUNT, insertAccessCount); - recordValues.Put(FIELD_REJECT_COUNT, insertRejectCount); - - if (!PermissionRecordRepository::GetInstance().RemoveRecordValues(rec)) { - return false; - } - break; - } - } - insertValues.emplace_back(recordValues); - return PermissionRecordRepository::GetInstance().AddRecordValues(insertValues); + PermissionUsedRecordCache::GetInstance().AddVisitorRecord(record); + return true; } bool PermissionRecordManager::GetPermissionsRecord(int32_t visitorId, const std::string& permissionName, @@ -184,6 +143,10 @@ int32_t PermissionRecordManager::AddPermissionUsedRecord(AccessTokenID tokenID, ACCESSTOKEN_LOG_DEBUG(LABEL, "Invalid token type"); return Constant::SUCCESS; } + int32_t opCode = -1; + if (!Constant::TransferPermissionToOpcode(permissionName, opCode)) { + return Constant::FAILURE; + } Utils::UniqueWriteGuard lk(this->rwLock_); int32_t visitorId; @@ -287,13 +250,18 @@ bool PermissionRecordManager::GetRecordsFromDB(const PermissionUsedRequest& requ bundleRecord.isRemote = visitor.GetInt(FIELD_IS_REMOTE_DEVICE); bundleRecord.deviceId = visitor.GetString(FIELD_DEVICE_ID); bundleRecord.bundleName = visitor.GetString(FIELD_BUNDLE_NAME); - + + if (!request.permissionList.empty()) { + PermissionUsedRecordCache::GetInstance().GetVisitorRecord(visitor.GetInt(FIELD_ID), + request.permissionList, findRecordsValues); + } else { + PermissionUsedRecordCache::GetInstance().GetVisitorRecord(visitor.GetInt(FIELD_ID), findRecordsValues); + } if (!findRecordsValues.empty()) { if (!GetRecords(request.flag, findRecordsValues, bundleRecord, result)) { return false; } } - if (!bundleRecord.permissionRecords.empty()) { result.bundleRecords.emplace_back(bundleRecord); } @@ -374,28 +342,57 @@ void PermissionRecordManager::ExecuteDeletePermissionRecordTask() int32_t PermissionRecordManager::DeletePermissionRecord(int32_t days) { Utils::UniqueWriteGuard lk(this->rwLock_); - GenericValues nullValues; - std::vector deleteRecordValues; - if (!PermissionRecordRepository::GetInstance().FindRecordValues(nullValues, nullValues, deleteRecordValues)) { + GenericValues countValue; + if (!PermissionRecordRepository::GetInstance().CountRecordValues(countValue)) { return Constant::FAILURE; } - - size_t deleteSize = 0; - if (deleteRecordValues.size() > Constant::MAX_TOTAL_RECORD) { - deleteSize = deleteRecordValues.size() - Constant::MAX_TOTAL_RECORD; - for (size_t i = 0; i < deleteSize; ++i) { - PermissionRecordRepository::GetInstance().RemoveRecordValues(deleteRecordValues[i]); + int64_t total = countValue.GetInt64("COUNT"); + if (total > Constant::MAX_TOTAL_RECORD) { + int32_t excessiveSize = total - Constant::MAX_TOTAL_RECORD; + if (!PermissionRecordRepository::GetInstance().DeleteExcessiveSizeRecordValues(excessiveSize)) { + return Constant::FAILURE; } } + GenericValues andConditionValues; int64_t deleteTimestamp = TimeUtil::GetCurrentTimestamp() - days; - for (size_t i = deleteSize; i < deleteRecordValues.size(); ++i) { - if (deleteRecordValues[i].GetInt64(FIELD_TIMESTAMP) < deleteTimestamp) { - PermissionRecordRepository::GetInstance().RemoveRecordValues(deleteRecordValues[i]); - } + andConditionValues.Put(FIELD_TIMESTAMP_END, deleteTimestamp); + if (!PermissionRecordRepository::GetInstance().DeleteExpireRecordsValues(andConditionValues)) { + return Constant::FAILURE; } return Constant::SUCCESS; } +void PermissionRecordManager::ExecuteReadRecordBufferTask() +{ + if (readRecordBufferTaskWorker_.GetCurTaskNum() > 1) { + ACCESSTOKEN_LOG_INFO(LABEL, "Already has read record buffer task!"); + return; + } + auto readRecordBufferTask = [this]() { + ACCESSTOKEN_LOG_DEBUG(LABEL, "ReadRecordBuffer task called"); + ReadRecordBufferToDB(); + }; + readRecordBufferTaskWorker_.AddTask(readRecordBufferTask); +} + +void PermissionRecordManager::ReadRecordBufferToDB() +{ + static const int32_t RETRY_SLEEP_TIME_MS = 5000; + while (1) { + auto retrySleepTime = std::chrono::milliseconds(RETRY_SLEEP_TIME_MS); + std::this_thread::sleep_for(retrySleepTime); + if (PermissionUsedRecordCache::GetInstance().GetReadableSize() != 0) { + Utils::UniqueWriteGuard lk(this->rwLock_); + PermissionUsedRecordCache::GetInstance().ReadVisitorRecordBuffer(); + if (PermissionUsedRecordCache::GetInstance().WriteRecordsToDB()) { + ACCESSTOKEN_LOG_INFO(LABEL, "ReadRecordBufferToDB(): Write to db"); + } + } else { + ACCESSTOKEN_LOG_INFO(LABEL, "ReadRecordBufferToDB(): No record to write"); + } + } +} + std::string PermissionRecordManager::DumpRecordInfo(const std::string& bundleName, const std::string& permissionName) { ACCESSTOKEN_LOG_DEBUG(LABEL, "Entry, bundleName=%{public}s, permissionName=%{public}s", diff --git a/services/privacymanager/src/record/permission_record_repository.cpp b/services/privacymanager/src/record/permission_record_repository.cpp index 7f053023bd23ee1c29fd695c4a052911a13da894..be0f73b8304509b7bb809efda7a6d21d4aca4456 100644 --- a/services/privacymanager/src/record/permission_record_repository.cpp +++ b/services/privacymanager/src/record/permission_record_repository.cpp @@ -71,6 +71,34 @@ bool PermissionRecordRepository::RemoveRecordValues(const GenericValues& conditi } return true; } + +int32_t PermissionRecordRepository::CountRecordValues(GenericValues& resultValues) +{ + if (PermissionUsedRecordDb::GetInstance().Count(PermissionUsedRecordDb::PERMISSION_RECORD, resultValues) + != PermissionUsedRecordDb::SUCCESS) { + return false; + } + return true; +} + +bool PermissionRecordRepository::DeleteExpireRecordsValues(const GenericValues& andConditions) +{ + if (PermissionUsedRecordDb::GetInstance().DeleteExpireRecords(PermissionUsedRecordDb::PERMISSION_RECORD, + andConditions) != PermissionUsedRecordDb::SUCCESS) { + ACCESSTOKEN_LOG_ERROR(LABEL, "PERMISSION_RECORD delete fail"); + return false; + } + return true; +} +bool PermissionRecordRepository::DeleteExcessiveSizeRecordValues(int32_t excessiveSize) +{ + if (PermissionUsedRecordDb::GetInstance().DeleteExcessiveRecords(PermissionUsedRecordDb::PERMISSION_RECORD, + excessiveSize) != PermissionUsedRecordDb::SUCCESS) { + ACCESSTOKEN_LOG_ERROR(LABEL, "PERMISSION_RECORD delete fail"); + return false; + } + return true; +} } // namespace AccessToken } // namespace Security } // namespace OHOS \ No newline at end of file diff --git a/services/privacymanager/src/record/permission_used_record_cache.cpp b/services/privacymanager/src/record/permission_used_record_cache.cpp new file mode 100644 index 0000000000000000000000000000000000000000..78723d2d10a1d22eccd839adae9b9c6862819ab2 --- /dev/null +++ b/services/privacymanager/src/record/permission_used_record_cache.cpp @@ -0,0 +1,270 @@ +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "permission_used_record_cache.h" +#include +#include "accesstoken_log.h" +#include "constant.h" +#include "generic_values.h" +#include "permission_record.h" +#include "permission_record_manager.h" +#include "permission_record_repository.h" +#include "permission_used_record_db.h" +#include "time_util.h" +#include "to_string.h" + +namespace OHOS { +namespace Security { +namespace AccessToken { +namespace { +static constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { + LOG_CORE, SECURITY_DOMAIN_PRIVACY, "permission_used_record_cache" +}; +} +int32_t PermissionUsedRecordCache::readableSize = 0; +int32_t PermissionUsedRecordCache::writePos = 0; +int32_t PermissionUsedRecordCache::readPos = 0; +std::vector PermissionUsedRecordCache::recordBuffer; +std::vector PermissionUsedRecordCache::writeToDbBuffer; +std::map> PermissionUsedRecordCache::visitorRecord; + +PermissionUsedRecordCache& PermissionUsedRecordCache::GetInstance() +{ + static PermissionUsedRecordCache instance; + return instance; +} +int32_t PermissionUsedRecordCache::AddVisitorRecord(PermissionRecord& record) +{ + int64_t insertTimestamp = record.timestamp; + int64_t insertAccessDuration = record.accessDuration; + int32_t insertAccessCount = record.accessCount; + int32_t insertRejectCount = record.rejectCount; + auto findVisitor = visitorRecord.find(record.visitorId); + if (findVisitor == visitorRecord.end()) { + ACCESSTOKEN_LOG_INFO(LABEL, "First add visitor"); + WriteVisitorRecordBuffer(record, false); + return Constant::SUCCESS; + } + std::vector writeExistedIndex = findVisitor->second; + for (auto index : writeExistedIndex) { + if (record.opCode == recordBuffer[index].opCode + && insertTimestamp-recordBuffer[index].timestamp < Constant::PRECISE) { + Utils::UniqueWriteGuard infoGuard(this->cacheLock_); + ACCESSTOKEN_LOG_INFO(LABEL, "Merge the same permission records within 1 minute, index = %{public}d", index); + if (insertTimestamp > recordBuffer[index].timestamp) { + recordBuffer[index].timestamp =insertTimestamp; + } + recordBuffer[index].accessDuration += insertAccessDuration; + recordBuffer[index].accessCount += insertAccessCount; + recordBuffer[index].rejectCount += insertRejectCount; + return Constant::SUCCESS; + } + } + if (writeExistedIndex.size() == MAX_RECORD_SIZE) { + Utils::UniqueWriteGuard infoGuard(this->cacheLock_); + int32_t earliest = writeExistedIndex[0]; + for (int32_t i : writeExistedIndex) { + if (recordBuffer[earliest].timestamp < recordBuffer[i].timestamp) { + earliest = i; + } + } + ACCESSTOKEN_LOG_INFO(LABEL, "More than 10 records, covering the earliest records, index =%{public}d", + earliest); + if (recordBuffer[earliest].timestamp <= record.timestamp) { + recordBuffer[earliest] = record; + } + return Constant::SUCCESS; + } + ACCESSTOKEN_LOG_INFO(LABEL, "No merge and less than 10 records"); + WriteVisitorRecordBuffer(record, true); + return Constant::SUCCESS; +} + +void PermissionUsedRecordCache::WriteVisitorRecordBuffer(PermissionRecord& record, bool isExisted) +{ + Utils::UniqueWriteGuard infoGuard(this->cacheLock_); + writePos %= MAX_RECORD_BUFFER_SIZE; + readPos %= MAX_RECORD_BUFFER_SIZE; + if (recordBuffer.capacity() < MAX_RECORD_BUFFER_SIZE) { + recordBuffer.push_back(record); + } else { + recordBuffer[writePos]=record; + } + if (!isExisted) { + std::vector writeIndex; + writeIndex.push_back(writePos); + visitorRecord.insert(std::make_pair(record.visitorId, writeIndex)); + } else { + visitorRecord[record.visitorId].push_back(writePos); + } + writePos++; + readableSize++; +} +void PermissionUsedRecordCache::ReadVisitorRecordBuffer() +{ + Utils::UniqueWriteGuard infoGuard(this->cacheLock_); + readPos %= MAX_RECORD_BUFFER_SIZE; + writePos %= MAX_RECORD_BUFFER_SIZE; + if (readPos < writePos) { + for (int32_t i = readPos; i < writePos; i++) { + ACCESSTOKEN_LOG_INFO(LABEL, "WriteToDbBuffer.push_back: position = %{public}d", i); + writeToDbBuffer.push_back(recordBuffer[i]); + } + } else { + for (int32_t i = readPos; i < MAX_RECORD_BUFFER_SIZE; i++) { + ACCESSTOKEN_LOG_INFO(LABEL, "WriteToDbBuffer.push_back: position = %{public}d", i); + writeToDbBuffer.push_back(recordBuffer[i]); + } + for (int32_t i = 0; i < writePos; i++) { + ACCESSTOKEN_LOG_INFO(LABEL, "WriteToDbBuffer.push_back: position = %{public}d", i); + writeToDbBuffer.push_back(recordBuffer[i]); + } + } + readPos = writePos; + readableSize = 0; + ClearVisitorRecord(); +} + +bool PermissionUsedRecordCache::WriteRecordsToDB() +{ + int64_t curTimestamp = TimeUtil::GetCurrentTimestamp(); + Utils::UniqueWriteGuard infoGuard(this->cacheLock_); + std::vector insertValues; + for (auto record : writeToDbBuffer) { + if (record.visitorId != -1 && curTimestamp - record.timestamp >= Constant::PRECISE) { + GenericValues recordValues; + PermissionRecord::TranslationIntoGenericValues(record, recordValues); + insertValues.emplace_back(recordValues); + } else if (record.visitorId != -1 && curTimestamp - record.timestamp < Constant::PRECISE) { + AddVisitorRecord(record); + } + } + std::vector().swap(writeToDbBuffer); + ACCESSTOKEN_LOG_INFO(LABEL, "Clear writeToDbBuffer"); + if (!insertValues.empty()) { + if (!PermissionRecordRepository::GetInstance().AddRecordValues(insertValues)) { + return false; + } + } + return true; +} + +void PermissionUsedRecordCache::ClearVisitorRecord() +{ + Utils::UniqueWriteGuard infoGuard(this->cacheLock_); + ACCESSTOKEN_LOG_INFO(LABEL, "ClearVisitorRecord"); + visitorRecord.clear(); +} + +int32_t PermissionUsedRecordCache::RemoveVisitorRecord(int32_t visitorId) +{ + std::vector deleteVisitorRecord; + if (GetDeleteVisitorRecord(visitorId, deleteVisitorRecord) == Constant::SUCCESS) { + Utils::UniqueWriteGuard infoGuard(this->cacheLock_); + for (int32_t index : deleteVisitorRecord) { + recordBuffer[index].visitorId = -1; + } + } + Utils::UniqueWriteGuard infoGuard(this->cacheLock_); + for (size_t i = 0; i < writeToDbBuffer.size(); i++) { + if (writeToDbBuffer[i].visitorId == visitorId) { + writeToDbBuffer[i].visitorId = -1; + } + } + return Constant::SUCCESS; +} + +int32_t PermissionUsedRecordCache::GetDeleteVisitorRecord(int32_t visitorId, std::vector& deleteVisitorRecord) +{ + Utils::UniqueWriteGuard infoGuard(this->cacheLock_); + auto findVisitor = visitorRecord.find(visitorId); + if (findVisitor == visitorRecord.end()) { + ACCESSTOKEN_LOG_INFO(LABEL, "There is no such visitorid record"); + return Constant::FAILURE; + } + deleteVisitorRecord = findVisitor->second; + visitorRecord.erase(findVisitor); + ACCESSTOKEN_LOG_INFO(LABEL, "The visitorid record has been found"); + return Constant::SUCCESS; +} +void PermissionUsedRecordCache::GetVisitorRecord(int32_t visitor, + const std::vector& permissionList, std::vector& findRecordsValues) +{ + std::set opCodeList; + for (auto permission : permissionList) { + int32_t opCode = Constant::OP_INVALID; + if (Constant::TransferPermissionToOpcode(permission, opCode)) { + opCodeList.insert(opCode); + } + } + Utils::UniqueWriteGuard infoGuard(this->cacheLock_); + auto findVisitor = visitorRecord.find(visitor); + if (findVisitor != visitorRecord.end()) { + for (int32_t index : findVisitor->second) { + PermissionRecord record = recordBuffer[index]; + std::string tmpPermissionName; + if (opCodeList.find(record.opCode) != opCodeList.end()) { + GenericValues recordValues; + PermissionRecord::TranslationIntoGenericValues(record, recordValues); + findRecordsValues.emplace_back(recordValues); + ACCESSTOKEN_LOG_INFO(LABEL, "Find recordValues visitorId = %{public}d, opCode = %{public}d ", + record.visitorId, record.opCode); + } + } + } + + for (auto record : writeToDbBuffer) { + if (record.visitorId == visitor && (opCodeList.find(record.opCode) != opCodeList.end())) { + GenericValues recordValues; + PermissionRecord::TranslationIntoGenericValues(record, recordValues); + findRecordsValues.emplace_back(recordValues); + ACCESSTOKEN_LOG_INFO(LABEL, "Find recordValues visitorId = %{public}d, opCode = %{public}d ", + record.visitorId, record.opCode); + } + } +} +void PermissionUsedRecordCache::GetVisitorRecord(int32_t visitor, std::vector& findRecordsValues) +{ + Utils::UniqueWriteGuard infoGuard(this->cacheLock_); + auto findVisitor = visitorRecord.find(visitor); + if (findVisitor != visitorRecord.end()) { + for (int32_t index : findVisitor->second) { + PermissionRecord record = recordBuffer[index]; + GenericValues recordValues; + PermissionRecord::TranslationIntoGenericValues(record, recordValues); + findRecordsValues.emplace_back(recordValues); + ACCESSTOKEN_LOG_INFO(LABEL, "Find recordValues visitorId = %{public}d, opCode = %{public}d ", + record.visitorId, record.opCode); + } + } + for (auto record : writeToDbBuffer) { + if (record.visitorId == visitor) { + GenericValues recordValues; + PermissionRecord::TranslationIntoGenericValues(record, recordValues); + findRecordsValues.emplace_back(recordValues); + ACCESSTOKEN_LOG_INFO(LABEL, "Find recordValues visitorId = %{public}d, opCode = %{public}d ", + record.visitorId, record.opCode); + } + } +} + +int32_t PermissionUsedRecordCache::GetReadableSize() +{ + Utils::UniqueWriteGuard infoGuard(this->cacheLock_); + return readableSize; +} +} // namespace AccessToken +} // namespace Security +} // namespace OHOS \ No newline at end of file diff --git a/services/privacymanager/src/service/privacy_manager_service.cpp b/services/privacymanager/src/service/privacy_manager_service.cpp index 1f9cecd49093288fff571c590dc68b9b9acf3184..a862cbc279015038323379b5899e46753a060712 100644 --- a/services/privacymanager/src/service/privacy_manager_service.cpp +++ b/services/privacymanager/src/service/privacy_manager_service.cpp @@ -62,6 +62,8 @@ void PrivacyManagerService::OnStart() return; } ACCESSTOKEN_LOG_INFO(LABEL, "Congratulations, PrivacyManagerService start successfully!"); + ACCESSTOKEN_LOG_INFO(LABEL, "ExecuteReadRecordBufferTask"); + PermissionRecordManager::GetInstance().ExecuteReadRecordBufferTask(); } void PrivacyManagerService::OnStop()