From 54a17ad39d5a5a40b8a627bbfc6074925f1b1e11 Mon Sep 17 00:00:00 2001 From: Stanislav Zholnin Date: Thu, 1 Apr 2021 13:07:26 +0100 Subject: [PATCH] Deduplicate discrete operation before delivering result. Before returning result from the API, we go through the list of all AttributedOpEntries and those which have the same timestamp are merged into single AttributedOpEntry without losing any information (it is still possible to query AttributedOpEntry with different flags / uidstates and get all the same information). This CL addresses issue with duplication due to accesses with different flags / uidstates. Test: in development Bug: 176965672 Bug: 183961838 Change-Id: I319dd321a3bfddf0855c10213c49824e9599eb66 --- core/java/android/app/AppOpsManager.java | 45 ++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java index df9530fee68a3..dd5e7f35dedb4 100644 --- a/core/java/android/app/AppOpsManager.java +++ b/core/java/android/app/AppOpsManager.java @@ -6996,6 +6996,20 @@ public class AppOpsManager { } result.add(entry); } + nAccesses = result.size(); + int i = 0; + for (int j = 0, k = 0; j < nAccesses; i++, j = k) { + long currentAccessTime = result.get(j).getLastAccessTime(OP_FLAGS_ALL); + k = j + 1; + while(k < nAccesses && + result.get(k).getLastAccessTime(OP_FLAGS_ALL) == currentAccessTime) { + k++; + } + result.set(i, mergeAttributedOpEntries(result.subList(j, k))); + } + for (; i < nAccesses; i++) { + result.remove(result.size() - 1); + } return result; } @@ -9819,4 +9833,35 @@ public class AppOpsManager { } } } + + private static AttributedOpEntry mergeAttributedOpEntries(List opEntries) { + if (opEntries.size() == 1) { + return opEntries.get(0); + } + LongSparseArray accessEvents = new LongSparseArray<>(); + LongSparseArray rejectEvents = new LongSparseArray<>(); + int opCount = opEntries.size(); + for (int i = 0; i < opCount; i++) { + AttributedOpEntry a = opEntries.get(i); + ArraySet keys = a.collectKeys(); + final int keyCount = keys.size(); + for (int k = 0; k < keyCount; k++) { + final long key = keys.valueAt(k); + + final int uidState = extractUidStateFromKey(key); + final int flags = extractFlagsFromKey(key); + + NoteOpEvent access = a.getLastAccessEvent(uidState, uidState, flags); + NoteOpEvent reject = a.getLastRejectEvent(uidState, uidState, flags); + + if (access != null) { + accessEvents.append(key, access); + } + if (reject != null) { + rejectEvents.append(key, reject); + } + } + } + return new AttributedOpEntry(opEntries.get(0).mOp, false, accessEvents, rejectEvents); + } }