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