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
This commit is contained in:
Stanislav Zholnin
2021-04-01 13:07:26 +01:00
parent 41b21288eb
commit 54a17ad39d

View File

@@ -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<AttributedOpEntry> opEntries) {
if (opEntries.size() == 1) {
return opEntries.get(0);
}
LongSparseArray<AppOpsManager.NoteOpEvent> accessEvents = new LongSparseArray<>();
LongSparseArray<AppOpsManager.NoteOpEvent> rejectEvents = new LongSparseArray<>();
int opCount = opEntries.size();
for (int i = 0; i < opCount; i++) {
AttributedOpEntry a = opEntries.get(i);
ArraySet<Long> 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);
}
}