• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022 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 "permission_used_record_cache.h"
17 #include "accesstoken_log.h"
18 #include "constant.h"
19 #include "generic_values.h"
20 #include "permission_record.h"
21 #include "permission_record_manager.h"
22 #include "permission_record_node.h"
23 #include "permission_record_repository.h"
24 #include "permission_used_record_db.h"
25 #include "privacy_field_const.h"
26 #include "time_util.h"
27 
28 namespace OHOS {
29 namespace Security {
30 namespace AccessToken {
31 namespace {
32 static constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {
33     LOG_CORE, SECURITY_DOMAIN_PRIVACY, "PermissionUsedRecordCache"
34 };
35 }
36 
GetInstance()37 PermissionUsedRecordCache& PermissionUsedRecordCache::GetInstance()
38 {
39     static PermissionUsedRecordCache instance;
40     return instance;
41 }
42 
AddRecordToBuffer(const PermissionRecord & record)43 void PermissionUsedRecordCache::AddRecordToBuffer(const PermissionRecord& record)
44 {
45     if (nextPersistTimestamp_ == 0) {
46         nextPersistTimestamp_ = record.timestamp + INTERVAL;
47     }
48     std::shared_ptr<PermissionUsedRecordNode> curFindMergePos;
49     std::shared_ptr<PermissionUsedRecordNode> persistPendingBufferHead;
50     std::shared_ptr<PermissionUsedRecordNode> persistPendingBufferEnd = nullptr;
51     PermissionRecord mergedRecord = record;
52     {
53         Utils::UniqueWriteGuard<Utils::RWLock> lock1(this->cacheLock1_);
54         curFindMergePos = curRecordBufferPos_;
55         persistPendingBufferHead = recordBufferHead_;
56         int32_t remainCount = 0;
57         while (curFindMergePos != recordBufferHead_) {
58             auto pre = curFindMergePos->pre.lock();
59             if ((record.timestamp - curFindMergePos->record.timestamp) >= INTERVAL) {
60                 persistPendingBufferEnd = curFindMergePos;
61                 break;
62             } else if (curFindMergePos->record.tokenId == record.tokenId &&
63                 record.opCode == curFindMergePos->record.opCode &&
64                 record.status == curFindMergePos->record.status &&
65                 (record.timestamp - curFindMergePos->record.timestamp) <= Constant::PRECISE) {
66                 MergeRecord(mergedRecord, curFindMergePos);
67             } else {
68                 remainCount++;
69             }
70             curFindMergePos = pre;
71         }
72         AddRecordNode(mergedRecord); // refresh curRecordBUfferPos and readableSize
73         remainCount++;
74         if (persistPendingBufferEnd != nullptr) {
75             ResetRecordBuffer(remainCount, persistPendingBufferEnd);
76         }
77     }
78     if (persistPendingBufferEnd != nullptr) {
79         AddToPersistQueue(persistPendingBufferHead);
80     }
81 }
82 
MergeRecord(PermissionRecord & record,std::shared_ptr<PermissionUsedRecordNode> curFindMergePos)83 void PermissionUsedRecordCache::MergeRecord(PermissionRecord& record,
84     std::shared_ptr<PermissionUsedRecordNode> curFindMergePos)
85 {
86     record.accessDuration += curFindMergePos->record.accessDuration;
87     record.accessCount += curFindMergePos->record.accessCount;
88     record.rejectCount += curFindMergePos->record.rejectCount;
89     if (curRecordBufferPos_ == curFindMergePos) {
90         curRecordBufferPos_ = curRecordBufferPos_->pre.lock();
91     }
92     DeleteRecordNode(curFindMergePos); // delete old same node
93     readableSize_--;
94 }
95 
AddToPersistQueue(const std::shared_ptr<PermissionUsedRecordNode> persistPendingBufferHead)96 void PermissionUsedRecordCache::AddToPersistQueue(
97     const std::shared_ptr<PermissionUsedRecordNode> persistPendingBufferHead)
98 {
99     bool startPersist = false;
100     {
101         Utils::UniqueWriteGuard<Utils::RWLock> lock2(this->cacheLock2_);
102         persistPendingBufferQueue_.emplace_back(persistPendingBufferHead);
103         if ((TimeUtil::GetCurrentTimestamp() >= nextPersistTimestamp_ ||
104             readableSize_ >= MAX_PERSIST_SIZE) && !persistIsRunning_) {
105             startPersist = true;
106         }
107     }
108     if (startPersist) {
109         ExecuteReadRecordBufferTask();
110     }
111 }
112 
ExecuteReadRecordBufferTask()113 void PermissionUsedRecordCache::ExecuteReadRecordBufferTask()
114 {
115     if (readRecordBufferTaskWorker_.GetCurTaskNum() > 1) {
116         ACCESSTOKEN_LOG_INFO(LABEL, "Already has read record buffer task!");
117         return;
118     }
119     auto readRecordBufferTask = [this]() {
120         ACCESSTOKEN_LOG_INFO(LABEL, "ReadRecordBuffer task called");
121         PersistPendingRecords();
122     };
123     readRecordBufferTaskWorker_.AddTask(readRecordBufferTask);
124 }
125 
PersistPendingRecords()126 int32_t PermissionUsedRecordCache::PersistPendingRecords()
127 {
128     std::shared_ptr<PermissionUsedRecordNode> persistPendingBufferHead;
129     bool isEmpty;
130     std::vector<GenericValues> insertValues;
131     {
132         Utils::UniqueReadGuard<Utils::RWLock> lock2(this->cacheLock2_);
133         isEmpty = persistPendingBufferQueue_.empty();
134         persistIsRunning_ = true;
135         nextPersistTimestamp_ = TimeUtil::GetCurrentTimestamp() + INTERVAL;
136     }
137     while (!isEmpty) {
138         {
139             Utils::UniqueWriteGuard<Utils::RWLock> lock2(this->cacheLock2_);
140             persistPendingBufferHead = persistPendingBufferQueue_[0];
141             persistPendingBufferQueue_.erase(persistPendingBufferQueue_.begin());
142         }
143         std::shared_ptr<PermissionUsedRecordNode> curPendingRecordNode =
144             persistPendingBufferHead->next;
145         while (curPendingRecordNode != nullptr) {
146             auto next = curPendingRecordNode->next;
147             GenericValues tmpRecordValues;
148             PermissionRecord tmpRecord = curPendingRecordNode->record;
149             PermissionRecord::TranslationIntoGenericValues(tmpRecord, tmpRecordValues);
150             insertValues.emplace_back(tmpRecordValues);
151             DeleteRecordNode(curPendingRecordNode);
152             curPendingRecordNode = next;
153         }
154         if (!insertValues.empty() && !PermissionRecordRepository::GetInstance().AddRecordValues(insertValues)) {
155             ACCESSTOKEN_LOG_ERROR(LABEL, "Failed to persist pending records");
156         }
157         {
158             Utils::UniqueReadGuard<Utils::RWLock> lock2(this->cacheLock2_);
159             isEmpty = persistPendingBufferQueue_.empty();
160         }
161     }
162     {
163         Utils::UniqueReadGuard<Utils::RWLock> lock2(this->cacheLock2_);
164         if (isEmpty) { // free persistPendingBufferQueue
165             std::vector<std::shared_ptr<PermissionUsedRecordNode>> tmpPersistPendingBufferQueue;
166             std::swap(tmpPersistPendingBufferQueue, persistPendingBufferQueue_);
167         }
168         persistIsRunning_ = false;
169     }
170     return true;
171 }
172 
RemoveRecords(const AccessTokenID tokenId)173 int32_t PermissionUsedRecordCache::RemoveRecords(const AccessTokenID tokenId)
174 {
175     std::shared_ptr<PermissionUsedRecordNode> curFindDeletePos;
176     std::shared_ptr<PermissionUsedRecordNode> persistPendingBufferHead;
177     std::shared_ptr<PermissionUsedRecordNode> persistPendingBufferEnd = nullptr;
178 
179     {
180         int32_t countPersistPendingNode = 0;
181         Utils::UniqueWriteGuard<Utils::RWLock> lock1(this->cacheLock1_);
182         curFindDeletePos = recordBufferHead_->next;
183         persistPendingBufferHead = recordBufferHead_;
184         while (curFindDeletePos != nullptr) {
185             auto next = curFindDeletePos->next;
186             if (curFindDeletePos->record.tokenId == tokenId) {
187                 if (curRecordBufferPos_ == curFindDeletePos) {
188                     curRecordBufferPos_ = curFindDeletePos->pre.lock();
189                 }
190                 DeleteRecordNode(curFindDeletePos);
191                 readableSize_--;
192             } else if (TimeUtil::GetCurrentTimestamp() -
193                 curFindDeletePos->record.timestamp >= INTERVAL) {
194                 persistPendingBufferEnd = curFindDeletePos;
195                 countPersistPendingNode++;
196             }
197             curFindDeletePos = next;
198         }
199         if (countPersistPendingNode != 0) { // refresh recordBufferHead
200             int32_t remainCount = readableSize_ - countPersistPendingNode;
201             ResetRecordBuffer(remainCount, persistPendingBufferEnd);
202         }
203     }
204     RemoveFromPersistQueueAndDatabase(tokenId);
205     if (persistPendingBufferEnd != nullptr) { // add to queue
206         AddToPersistQueue(persistPendingBufferHead);
207     }
208     return Constant::SUCCESS;
209 }
210 
RemoveFromPersistQueueAndDatabase(const AccessTokenID tokenId)211 void PermissionUsedRecordCache::RemoveFromPersistQueueAndDatabase(const AccessTokenID tokenId)
212 {
213     {
214         std::shared_ptr<PermissionUsedRecordNode> curFindDeletePos;
215         Utils::UniqueWriteGuard<Utils::RWLock> lock2(this->cacheLock2_);
216         if (!persistPendingBufferQueue_.empty()) {
217             for (const auto& persistHead : persistPendingBufferQueue_) {
218                 curFindDeletePos = persistHead->next;
219                 while (curFindDeletePos != nullptr) {
220                     auto next = curFindDeletePos->next;
221                     if (curFindDeletePos->record.tokenId == tokenId) {
222                         DeleteRecordNode(curFindDeletePos);
223                     }
224                     curFindDeletePos = next;
225                 }
226             }
227         }
228     }
229     GenericValues record;
230     record.Put(PrivacyFiledConst::FIELD_TOKEN_ID, static_cast<int32_t>(tokenId));
231     PermissionRecordRepository::GetInstance().RemoveRecordValues(record); // remove from database
232 }
233 
GetRecords(const std::vector<std::string> & permissionList,const GenericValues & andConditionValues,const GenericValues & orConditionValues,std::vector<GenericValues> & findRecordsValues)234 void PermissionUsedRecordCache::GetRecords(const std::vector<std::string>& permissionList,
235     const GenericValues& andConditionValues, const GenericValues& orConditionValues,
236     std::vector<GenericValues>& findRecordsValues)
237 {
238     std::set<int32_t> opCodeList;
239     std::shared_ptr<PermissionUsedRecordNode> curFindPos;
240     std::shared_ptr<PermissionUsedRecordNode> persistPendingBufferHead;
241     std::shared_ptr<PermissionUsedRecordNode> persistPendingBufferEnd = nullptr;
242     int32_t countPersistPendingNode = 0;
243     AccessTokenID tokenId = andConditionValues.GetInt(PrivacyFiledConst::FIELD_TOKEN_ID);
244     TransferToOpcode(opCodeList, permissionList);
245     {
246         Utils::UniqueWriteGuard<Utils::RWLock> lock1(this->cacheLock1_);
247         curFindPos = recordBufferHead_->next;
248         persistPendingBufferHead = recordBufferHead_;
249         while (curFindPos != nullptr) {
250             auto next = curFindPos->next;
251             if (RecordCompare(tokenId, opCodeList, andConditionValues, curFindPos->record)) {
252                 GenericValues recordValues;
253                 PermissionRecord::TranslationIntoGenericValues(curFindPos->record, recordValues);
254                 findRecordsValues.emplace_back(recordValues);
255             }
256             if (TimeUtil::GetCurrentTimestamp() - curFindPos->record.timestamp >= INTERVAL) {
257                 persistPendingBufferEnd = curFindPos;
258                 countPersistPendingNode++;
259             }
260             curFindPos = next;
261         }
262         if (countPersistPendingNode != 0) { // refresh recordBufferHead
263             int32_t remainCount = readableSize_ - countPersistPendingNode;
264             ResetRecordBuffer(remainCount, persistPendingBufferEnd);
265         }
266     }
267     GetFromPersistQueueAndDatabase(opCodeList, andConditionValues,
268         orConditionValues, findRecordsValues);
269     if (countPersistPendingNode != 0) {
270         AddToPersistQueue(persistPendingBufferHead);
271     }
272 }
273 
GetFromPersistQueueAndDatabase(const std::set<int32_t> & opCodeList,const GenericValues & andConditionValues,const GenericValues & orConditionValues,std::vector<GenericValues> & findRecordsValues)274 void PermissionUsedRecordCache::GetFromPersistQueueAndDatabase(const std::set<int32_t>& opCodeList,
275     const GenericValues& andConditionValues, const GenericValues& orConditionValues,
276     std::vector<GenericValues>& findRecordsValues)
277 {
278     AccessTokenID tokenId = andConditionValues.GetInt(PrivacyFiledConst::FIELD_TOKEN_ID);
279     std::shared_ptr<PermissionUsedRecordNode> curFindPos;
280     {
281         Utils::UniqueWriteGuard<Utils::RWLock> lock2(this->cacheLock2_);
282         if (!persistPendingBufferQueue_.empty()) {
283             for (const auto& persistHead : persistPendingBufferQueue_) {
284                 curFindPos = persistHead->next;
285                 while (curFindPos != nullptr) {
286                     auto next = curFindPos->next;
287                     if (RecordCompare(tokenId, opCodeList, andConditionValues, curFindPos->record)) {
288                         GenericValues recordValues;
289                         PermissionRecord::TranslationIntoGenericValues(curFindPos->record, recordValues);
290                         findRecordsValues.emplace_back(recordValues);
291                     }
292                     curFindPos = next;
293                 }
294             }
295         }
296     }
297     if (!PermissionRecordRepository::GetInstance().FindRecordValues(
298         andConditionValues, orConditionValues, findRecordsValues)) { // find records from database
299         ACCESSTOKEN_LOG_ERROR(LABEL, "find records from database failed");
300     }
301 }
302 
ResetRecordBuffer(const int32_t remainCount,std::shared_ptr<PermissionUsedRecordNode> & persistPendingBufferEnd)303 void PermissionUsedRecordCache::ResetRecordBuffer(const int32_t remainCount,
304     std::shared_ptr<PermissionUsedRecordNode>& persistPendingBufferEnd)
305 {
306     readableSize_ = remainCount;
307     // refresh recordBufferHead
308     std::shared_ptr<PermissionUsedRecordNode> tmpRecordBufferHead =
309         std::make_shared<PermissionUsedRecordNode>();
310     tmpRecordBufferHead->next = persistPendingBufferEnd->next;
311     persistPendingBufferEnd->next.reset();
312     recordBufferHead_ = tmpRecordBufferHead;
313 
314     if (persistPendingBufferEnd == curRecordBufferPos_) {
315         // persistPendingBufferEnd == curRecordBufferPos, reset curRecordBufferPos
316         curRecordBufferPos_ = recordBufferHead_;
317     } else {
318         // recordBufferHead_->next->pre = persistPendingBufferEnd, reset recordBufferHead_->next->pre
319         recordBufferHead_->next->pre = recordBufferHead_;
320     }
321 }
322 
TransferToOpcode(std::set<int32_t> & opCodeList,const std::vector<std::string> & permissionList)323 void PermissionUsedRecordCache::TransferToOpcode(std::set<int32_t>& opCodeList,
324     const std::vector<std::string>& permissionList)
325 {
326     for (const auto& permission : permissionList) {
327         int32_t opCode = Constant::OP_INVALID;
328         Constant::TransferPermissionToOpcode(permission, opCode);
329         opCodeList.insert(opCode);
330     }
331 }
332 
RecordCompare(const AccessTokenID tokenId,const std::set<int32_t> & opCodeList,const GenericValues & andConditionValues,const PermissionRecord & record)333 bool PermissionUsedRecordCache::RecordCompare(const AccessTokenID tokenId, const std::set<int32_t>& opCodeList,
334     const GenericValues& andConditionValues, const PermissionRecord& record)
335 {
336     // compare tokenId
337     if (record.tokenId != tokenId) {
338         return false;
339     }
340     // compare opCode
341     if (!opCodeList.empty() && opCodeList.find(record.opCode) == opCodeList.end()) {
342         return false;
343     }
344     // compare timestamp
345     std::vector<std::string> andColumns = andConditionValues.GetAllKeys();
346     if (!andColumns.empty()) {
347         for (auto andColumn : andColumns) {
348             if (andColumn == PrivacyFiledConst::FIELD_TIMESTAMP_BEGIN &&
349                 record.timestamp < andConditionValues.GetInt64(andColumn)) {
350                 return false;
351             } else if (andColumn == PrivacyFiledConst::FIELD_TIMESTAMP_END &&
352                 record.timestamp > andConditionValues.GetInt64(andColumn)) {
353                 return false;
354             } else if (andColumn == PrivacyFiledConst::FIELD_TIMESTAMP &&
355                 record.timestamp != andConditionValues.GetInt64(andColumn)) {
356                 return false;
357             }
358         }
359     }
360     return true;
361 }
362 
FindTokenIdList(std::set<AccessTokenID> & tokenIdList)363 void PermissionUsedRecordCache::FindTokenIdList(std::set<AccessTokenID>& tokenIdList)
364 {
365     std::shared_ptr<PermissionUsedRecordNode> curFindPos;
366     {
367         // find tokenIdList from recordBuffer
368         Utils::UniqueWriteGuard<Utils::RWLock> lock1(this->cacheLock1_);
369         curFindPos = recordBufferHead_->next;
370         while (curFindPos != nullptr) {
371             auto next = curFindPos->next;
372             tokenIdList.emplace((AccessTokenID)curFindPos->record.tokenId);
373             curFindPos = next;
374         }
375     }
376     {
377         // find tokenIdList from BufferQueue
378         Utils::UniqueWriteGuard<Utils::RWLock> lock2(this->cacheLock2_);
379         if (!persistPendingBufferQueue_.empty()) {
380             for (auto persistHead : persistPendingBufferQueue_) {
381                 curFindPos = persistHead->next;
382                 while (curFindPos != nullptr) {
383                     auto next = curFindPos->next;
384                     tokenIdList.emplace((AccessTokenID)curFindPos->record.tokenId);
385                     curFindPos = next;
386                 }
387             }
388         }
389     }
390 }
391 
AddRecordNode(const PermissionRecord & record)392 void PermissionUsedRecordCache::AddRecordNode(const PermissionRecord& record)
393 {
394     std::shared_ptr<PermissionUsedRecordNode> tmpRecordNode = std::make_shared<PermissionUsedRecordNode>();
395     tmpRecordNode->record = record;
396     tmpRecordNode->pre = curRecordBufferPos_;
397     curRecordBufferPos_->next = tmpRecordNode;
398     curRecordBufferPos_ = curRecordBufferPos_->next;
399     readableSize_++;
400 }
401 
DeleteRecordNode(std::shared_ptr<PermissionUsedRecordNode> deleteRecordNode)402 void PermissionUsedRecordCache::DeleteRecordNode(std::shared_ptr<PermissionUsedRecordNode> deleteRecordNode)
403 {
404     std::shared_ptr<PermissionUsedRecordNode> pre = deleteRecordNode->pre.lock();
405     if (deleteRecordNode->next == nullptr) { // End of the linked list
406         pre->next = nullptr;
407     } else {
408         std::shared_ptr<PermissionUsedRecordNode> next = deleteRecordNode->next;
409         pre->next = next;
410         next->pre = pre;
411     }
412 }
413 } // namespace AccessToken
414 } // namespace Security
415 } // namespace OHOS