Introduce caching to DiscreteRegistry.
Cached representation of state on disk is kept in the memory after API query until next time data is dump to disk. Second and following API queries will not hit the disk. Other improvements and bug fixes. Bug: 176965672 Test: in development Change-Id: I583cba4c74487c79f023efd4b3ce2ee844351719
This commit is contained in:
@@ -49,8 +49,6 @@ import com.android.internal.annotations.GuardedBy;
|
||||
import com.android.internal.util.ArrayUtils;
|
||||
import com.android.internal.util.XmlUtils;
|
||||
|
||||
import libcore.util.EmptyArray;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
@@ -85,6 +83,8 @@ final class DiscreteRegistry {
|
||||
private static final String TAG = DiscreteRegistry.class.getSimpleName();
|
||||
|
||||
private static final long TIMELINE_HISTORY_CUTOFF = Duration.ofHours(24).toMillis();
|
||||
private static final long TIMELINE_QUANTIZATION = Duration.ofMinutes(1).toMillis();
|
||||
|
||||
private static final String TAG_HISTORY = "h";
|
||||
private static final String ATTR_VERSION = "v";
|
||||
private static final int CURRENT_VERSION = 1;
|
||||
@@ -107,6 +107,8 @@ final class DiscreteRegistry {
|
||||
private static final String ATTR_UID_STATE = "us";
|
||||
private static final String ATTR_FLAGS = "f";
|
||||
|
||||
private static final int OP_FLAGS_DISCRETE = OP_FLAG_SELF | OP_FLAG_TRUSTED_PROXIED;
|
||||
|
||||
// Lock for read/write access to on disk state
|
||||
private final Object mOnDiskLock = new Object();
|
||||
|
||||
@@ -119,6 +121,9 @@ final class DiscreteRegistry {
|
||||
@GuardedBy("mInMemoryLock")
|
||||
private DiscreteOps mDiscreteOps;
|
||||
|
||||
@GuardedBy("mOnDiskLock")
|
||||
private DiscreteOps mCachedOps = null;
|
||||
|
||||
DiscreteRegistry(Object inMemoryLock) {
|
||||
mInMemoryLock = inMemoryLock;
|
||||
mDiscreteAccessDir = new File(new File(Environment.getDataSystemDirectory(), "appops"),
|
||||
@@ -173,23 +178,25 @@ final class DiscreteRegistry {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
DiscreteOps discreteOps;
|
||||
synchronized (mInMemoryLock) {
|
||||
discreteOps = mDiscreteOps;
|
||||
mDiscreteOps = new DiscreteOps();
|
||||
}
|
||||
if (discreteOps.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
long currentTimeStamp = Instant.now().toEpochMilli();
|
||||
try {
|
||||
final File file = new File(mDiscreteAccessDir, currentTimeStamp + TIMELINE_FILE_SUFFIX);
|
||||
discreteOps.writeToFile(file);
|
||||
} catch (Throwable t) {
|
||||
Slog.e(TAG,
|
||||
"Error writing timeline state: " + t.getMessage() + " "
|
||||
+ Arrays.toString(t.getStackTrace()));
|
||||
DiscreteOps discreteOps;
|
||||
synchronized (mInMemoryLock) {
|
||||
discreteOps = mDiscreteOps;
|
||||
mDiscreteOps = new DiscreteOps();
|
||||
mCachedOps = null;
|
||||
}
|
||||
if (discreteOps.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
long currentTimeStamp = Instant.now().toEpochMilli();
|
||||
try {
|
||||
final File file = new File(mDiscreteAccessDir,
|
||||
currentTimeStamp + TIMELINE_FILE_SUFFIX);
|
||||
discreteOps.writeToFile(file);
|
||||
} catch (Throwable t) {
|
||||
Slog.e(TAG,
|
||||
"Error writing timeline state: " + t.getMessage() + " "
|
||||
+ Arrays.toString(t.getStackTrace()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -197,25 +204,33 @@ final class DiscreteRegistry {
|
||||
long endTimeMillis, @AppOpsManager.HistoricalOpsRequestFilter int filter, int uidFilter,
|
||||
@Nullable String packageNameFilter, @Nullable String[] opNamesFilter,
|
||||
@Nullable String attributionTagFilter, @AppOpsManager.OpFlags int flagsFilter) {
|
||||
writeAndClearAccessHistory();
|
||||
DiscreteOps discreteOps = new DiscreteOps();
|
||||
readDiscreteOpsFromDisk(discreteOps, beginTimeMillis, endTimeMillis, filter, uidFilter,
|
||||
packageNameFilter, opNamesFilter, attributionTagFilter, flagsFilter);
|
||||
DiscreteOps discreteOps = getAndCacheDiscreteOps();
|
||||
discreteOps.filter(beginTimeMillis, endTimeMillis, filter, uidFilter, packageNameFilter,
|
||||
opNamesFilter, attributionTagFilter, flagsFilter);
|
||||
discreteOps.applyToHistoricalOps(result);
|
||||
return;
|
||||
}
|
||||
|
||||
private void readDiscreteOpsFromDisk(DiscreteOps discreteOps, long beginTimeMillis,
|
||||
long endTimeMillis, @AppOpsManager.HistoricalOpsRequestFilter int filter, int uidFilter,
|
||||
@Nullable String packageNameFilter, @Nullable String[] opNamesFilter,
|
||||
@Nullable String attributionTagFilter, @AppOpsManager.OpFlags int flagsFilter) {
|
||||
private DiscreteOps getAndCacheDiscreteOps() {
|
||||
DiscreteOps discreteOps = new DiscreteOps();
|
||||
|
||||
synchronized (mOnDiskLock) {
|
||||
long historyBeginTimeMillis = Instant.now().minus(TIMELINE_HISTORY_CUTOFF,
|
||||
ChronoUnit.MILLIS).toEpochMilli();
|
||||
if (historyBeginTimeMillis > endTimeMillis) {
|
||||
return;
|
||||
synchronized (mInMemoryLock) {
|
||||
discreteOps.merge(mDiscreteOps);
|
||||
}
|
||||
beginTimeMillis = max(beginTimeMillis, historyBeginTimeMillis);
|
||||
if (mCachedOps == null) {
|
||||
mCachedOps = new DiscreteOps();
|
||||
readDiscreteOpsFromDisk(mCachedOps);
|
||||
}
|
||||
discreteOps.merge(mCachedOps);
|
||||
}
|
||||
return discreteOps;
|
||||
}
|
||||
|
||||
private void readDiscreteOpsFromDisk(DiscreteOps discreteOps) {
|
||||
synchronized (mOnDiskLock) {
|
||||
long beginTimeMillis = Instant.now().minus(TIMELINE_HISTORY_CUTOFF,
|
||||
ChronoUnit.MILLIS).toEpochMilli();
|
||||
|
||||
final File[] files = mDiscreteAccessDir.listFiles();
|
||||
if (files != null && files.length > 0) {
|
||||
@@ -229,8 +244,7 @@ final class DiscreteRegistry {
|
||||
if (timestamp < beginTimeMillis) {
|
||||
continue;
|
||||
}
|
||||
discreteOps.readFromFile(f, beginTimeMillis, endTimeMillis, filter, uidFilter,
|
||||
packageNameFilter, opNamesFilter, attributionTagFilter, flagsFilter);
|
||||
discreteOps.readFromFile(f, beginTimeMillis);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -251,15 +265,11 @@ final class DiscreteRegistry {
|
||||
@AppOpsManager.HistoricalOpsRequestFilter int filter, int dumpOp,
|
||||
@NonNull SimpleDateFormat sdf, @NonNull Date date, @NonNull String prefix,
|
||||
int nDiscreteOps) {
|
||||
DiscreteOps discreteOps = new DiscreteOps();
|
||||
synchronized (mOnDiskLock) {
|
||||
writeAndClearAccessHistory();
|
||||
String[] opNamesFilter = dumpOp == OP_NONE ? EmptyArray.STRING
|
||||
: new String[]{AppOpsManager.opToPublicName(dumpOp)};
|
||||
readDiscreteOpsFromDisk(discreteOps, 0, Instant.now().toEpochMilli(), filter,
|
||||
uidFilter, packageNameFilter, opNamesFilter, attributionTagFilter,
|
||||
OP_FLAGS_ALL);
|
||||
}
|
||||
DiscreteOps discreteOps = getAndCacheDiscreteOps();
|
||||
String[] opNamesFilter = dumpOp == OP_NONE ? null
|
||||
: new String[]{AppOpsManager.opToPublicName(dumpOp)};
|
||||
discreteOps.filter(0, Instant.now().toEpochMilli(), filter, uidFilter, packageNameFilter,
|
||||
opNamesFilter, attributionTagFilter, OP_FLAGS_ALL);
|
||||
discreteOps.dump(pw, sdf, date, prefix, nDiscreteOps);
|
||||
}
|
||||
|
||||
@@ -270,7 +280,7 @@ final class DiscreteRegistry {
|
||||
if (!isDiscreteUid(uid)) {
|
||||
return false;
|
||||
}
|
||||
if ((flags & (OP_FLAG_SELF | OP_FLAG_TRUSTED_PROXIED)) == 0) {
|
||||
if ((flags & (OP_FLAGS_DISCRETE)) == 0) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@@ -298,6 +308,19 @@ final class DiscreteRegistry {
|
||||
mUids = new ArrayMap<>();
|
||||
}
|
||||
|
||||
boolean isEmpty() {
|
||||
return mUids.isEmpty();
|
||||
}
|
||||
|
||||
void merge(DiscreteOps other) {
|
||||
int nUids = other.mUids.size();
|
||||
for (int i = 0; i < nUids; i++) {
|
||||
int uid = other.mUids.keyAt(i);
|
||||
DiscreteUidOps uidOps = other.mUids.valueAt(i);
|
||||
getOrCreateDiscreteUidOps(uid).merge(uidOps);
|
||||
}
|
||||
}
|
||||
|
||||
void addDiscreteAccess(int op, int uid, @NonNull String packageName,
|
||||
@Nullable String attributionTag, @AppOpsManager.OpFlags int flags,
|
||||
@AppOpsManager.UidState int uidState, long accessTime, long accessDuration) {
|
||||
@@ -305,6 +328,25 @@ final class DiscreteRegistry {
|
||||
uidState, accessTime, accessDuration);
|
||||
}
|
||||
|
||||
private void filter(long beginTimeMillis, long endTimeMillis,
|
||||
@AppOpsManager.HistoricalOpsRequestFilter int filter, int uidFilter,
|
||||
@Nullable String packageNameFilter, @Nullable String[] opNamesFilter,
|
||||
@Nullable String attributionTagFilter, @AppOpsManager.OpFlags int flagsFilter) {
|
||||
if ((filter & FILTER_BY_UID) != 0) {
|
||||
ArrayMap<Integer, DiscreteUidOps> uids = new ArrayMap<>();
|
||||
uids.put(uidFilter, getOrCreateDiscreteUidOps(uidFilter));
|
||||
mUids = uids;
|
||||
}
|
||||
int nUids = mUids.size();
|
||||
for (int i = nUids - 1; i >= 0; i--) {
|
||||
mUids.valueAt(i).filter(beginTimeMillis, endTimeMillis, filter, packageNameFilter,
|
||||
opNamesFilter, attributionTagFilter, flagsFilter);
|
||||
if (mUids.valueAt(i).isEmpty()) {
|
||||
mUids.removeAt(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void applyToHistoricalOps(AppOpsManager.HistoricalOps result) {
|
||||
int nUids = mUids.size();
|
||||
for (int i = 0; i < nUids; i++) {
|
||||
@@ -353,14 +395,7 @@ final class DiscreteRegistry {
|
||||
return result;
|
||||
}
|
||||
|
||||
boolean isEmpty() {
|
||||
return mUids.isEmpty();
|
||||
}
|
||||
|
||||
private void readFromFile(File f, long beginTimeMillis, long endTimeMillis,
|
||||
@AppOpsManager.HistoricalOpsRequestFilter int filter,
|
||||
int uidFilter, @Nullable String packageNameFilter, @Nullable String[] opNamesFilter,
|
||||
@Nullable String attributionTagFilter, @AppOpsManager.OpFlags int flagsFilter) {
|
||||
private void readFromFile(File f, long beginTimeMillis) {
|
||||
try {
|
||||
FileInputStream stream = new FileInputStream(f);
|
||||
TypedXmlPullParser parser = Xml.resolvePullParser(stream);
|
||||
@@ -377,12 +412,7 @@ final class DiscreteRegistry {
|
||||
while (XmlUtils.nextElementWithin(parser, depth)) {
|
||||
if (TAG_UID.equals(parser.getName())) {
|
||||
int uid = parser.getAttributeInt(null, ATTR_UID, -1);
|
||||
if ((filter & FILTER_BY_UID) != 0 && uid != uidFilter) {
|
||||
continue;
|
||||
}
|
||||
getOrCreateDiscreteUidOps(uid).deserialize(parser, beginTimeMillis,
|
||||
endTimeMillis, filter, packageNameFilter, opNamesFilter,
|
||||
attributionTagFilter, flagsFilter);
|
||||
getOrCreateDiscreteUidOps(uid).deserialize(parser, beginTimeMillis);
|
||||
}
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
@@ -400,6 +430,38 @@ final class DiscreteRegistry {
|
||||
mPackages = new ArrayMap<>();
|
||||
}
|
||||
|
||||
boolean isEmpty() {
|
||||
return mPackages.isEmpty();
|
||||
}
|
||||
|
||||
void merge(DiscreteUidOps other) {
|
||||
int nPackages = other.mPackages.size();
|
||||
for (int i = 0; i < nPackages; i++) {
|
||||
String packageName = other.mPackages.keyAt(i);
|
||||
DiscretePackageOps p = other.mPackages.valueAt(i);
|
||||
getOrCreateDiscretePackageOps(packageName).merge(p);
|
||||
}
|
||||
}
|
||||
|
||||
private void filter(long beginTimeMillis, long endTimeMillis,
|
||||
@AppOpsManager.HistoricalOpsRequestFilter int filter,
|
||||
@Nullable String packageNameFilter, @Nullable String[] opNamesFilter,
|
||||
@Nullable String attributionTagFilter, @AppOpsManager.OpFlags int flagsFilter) {
|
||||
if ((filter & FILTER_BY_PACKAGE_NAME) != 0) {
|
||||
ArrayMap<String, DiscretePackageOps> packages = new ArrayMap<>();
|
||||
packages.put(packageNameFilter, getOrCreateDiscretePackageOps(packageNameFilter));
|
||||
mPackages = packages;
|
||||
}
|
||||
int nPackages = mPackages.size();
|
||||
for (int i = nPackages - 1; i >= 0; i--) {
|
||||
mPackages.valueAt(i).filter(beginTimeMillis, endTimeMillis, filter, opNamesFilter,
|
||||
attributionTagFilter, flagsFilter);
|
||||
if (mPackages.valueAt(i).isEmpty()) {
|
||||
mPackages.removeAt(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void addDiscreteAccess(int op, @NonNull String packageName, @Nullable String attributionTag,
|
||||
@AppOpsManager.OpFlags int flags, @AppOpsManager.UidState int uidState,
|
||||
long accessTime, long accessDuration) {
|
||||
@@ -445,22 +507,12 @@ final class DiscreteRegistry {
|
||||
}
|
||||
}
|
||||
|
||||
void deserialize(TypedXmlPullParser parser, long beginTimeMillis,
|
||||
long endTimeMillis, @AppOpsManager.HistoricalOpsRequestFilter int filter,
|
||||
@Nullable String packageNameFilter,
|
||||
@Nullable String[] opNamesFilter, @Nullable String attributionTagFilter,
|
||||
@AppOpsManager.OpFlags int flagsFilter) throws Exception {
|
||||
void deserialize(TypedXmlPullParser parser, long beginTimeMillis) throws Exception {
|
||||
int depth = parser.getDepth();
|
||||
while (XmlUtils.nextElementWithin(parser, depth)) {
|
||||
if (TAG_PACKAGE.equals(parser.getName())) {
|
||||
String packageName = parser.getAttributeValue(null, ATTR_PACKAGE_NAME);
|
||||
if ((filter & FILTER_BY_PACKAGE_NAME) != 0
|
||||
&& !packageName.equals(packageNameFilter)) {
|
||||
continue;
|
||||
}
|
||||
getOrCreateDiscretePackageOps(packageName).deserialize(parser, beginTimeMillis,
|
||||
endTimeMillis, filter, opNamesFilter, attributionTagFilter,
|
||||
flagsFilter);
|
||||
getOrCreateDiscretePackageOps(packageName).deserialize(parser, beginTimeMillis);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -473,6 +525,10 @@ final class DiscreteRegistry {
|
||||
mPackageOps = new ArrayMap<>();
|
||||
}
|
||||
|
||||
boolean isEmpty() {
|
||||
return mPackageOps.isEmpty();
|
||||
}
|
||||
|
||||
void addDiscreteAccess(int op, @Nullable String attributionTag,
|
||||
@AppOpsManager.OpFlags int flags, @AppOpsManager.UidState int uidState,
|
||||
long accessTime, long accessDuration) {
|
||||
@@ -480,6 +536,35 @@ final class DiscreteRegistry {
|
||||
accessDuration);
|
||||
}
|
||||
|
||||
void merge(DiscretePackageOps other) {
|
||||
int nOps = other.mPackageOps.size();
|
||||
for (int i = 0; i < nOps; i++) {
|
||||
int opId = other.mPackageOps.keyAt(i);
|
||||
DiscreteOp op = other.mPackageOps.valueAt(i);
|
||||
getOrCreateDiscreteOp(opId).merge(op);
|
||||
}
|
||||
}
|
||||
|
||||
private void filter(long beginTimeMillis, long endTimeMillis,
|
||||
@AppOpsManager.HistoricalOpsRequestFilter int filter,
|
||||
@Nullable String[] opNamesFilter, @Nullable String attributionTagFilter,
|
||||
@AppOpsManager.OpFlags int flagsFilter) {
|
||||
int nOps = mPackageOps.size();
|
||||
for (int i = nOps - 1; i >= 0; i--) {
|
||||
int opId = mPackageOps.keyAt(i);
|
||||
if ((filter & FILTER_BY_OP_NAMES) != 0 && !ArrayUtils.contains(opNamesFilter,
|
||||
AppOpsManager.opToPublicName(opId))) {
|
||||
mPackageOps.removeAt(i);
|
||||
continue;
|
||||
}
|
||||
mPackageOps.valueAt(i).filter(beginTimeMillis, endTimeMillis, filter,
|
||||
attributionTagFilter, flagsFilter);
|
||||
if (mPackageOps.valueAt(i).isEmpty()) {
|
||||
mPackageOps.removeAt(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private DiscreteOp getOrCreateDiscreteOp(int op) {
|
||||
DiscreteOp result = mPackageOps.get(op);
|
||||
if (result == null) {
|
||||
@@ -519,20 +604,12 @@ final class DiscreteRegistry {
|
||||
}
|
||||
}
|
||||
|
||||
void deserialize(TypedXmlPullParser parser, long beginTimeMillis, long endTimeMillis,
|
||||
@AppOpsManager.HistoricalOpsRequestFilter int filter,
|
||||
@Nullable String[] opNamesFilter, @Nullable String attributionTagFilter,
|
||||
@AppOpsManager.OpFlags int flagsFilter) throws Exception {
|
||||
void deserialize(TypedXmlPullParser parser, long beginTimeMillis) throws Exception {
|
||||
int depth = parser.getDepth();
|
||||
while (XmlUtils.nextElementWithin(parser, depth)) {
|
||||
if (TAG_OP.equals(parser.getName())) {
|
||||
int op = parser.getAttributeInt(null, ATTR_OP_ID);
|
||||
if ((filter & FILTER_BY_OP_NAMES) != 0 && !ArrayUtils.contains(opNamesFilter,
|
||||
AppOpsManager.opToPublicName(op))) {
|
||||
continue;
|
||||
}
|
||||
getOrCreateDiscreteOp(op).deserialize(parser, beginTimeMillis, endTimeMillis,
|
||||
filter, attributionTagFilter, flagsFilter);
|
||||
getOrCreateDiscreteOp(op).deserialize(parser, beginTimeMillis);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -545,31 +622,66 @@ final class DiscreteRegistry {
|
||||
mAttributedOps = new ArrayMap<>();
|
||||
}
|
||||
|
||||
boolean isEmpty() {
|
||||
return mAttributedOps.isEmpty();
|
||||
}
|
||||
|
||||
void merge(DiscreteOp other) {
|
||||
int nTags = other.mAttributedOps.size();
|
||||
for (int i = 0; i < nTags; i++) {
|
||||
String tag = other.mAttributedOps.keyAt(i);
|
||||
List<DiscreteOpEvent> otherEvents = other.mAttributedOps.valueAt(i);
|
||||
List<DiscreteOpEvent> events = getOrCreateDiscreteOpEventsList(tag);
|
||||
mAttributedOps.put(tag, stableListMerge(events, otherEvents));
|
||||
}
|
||||
}
|
||||
|
||||
private void filter(long beginTimeMillis, long endTimeMillis,
|
||||
@AppOpsManager.HistoricalOpsRequestFilter int filter,
|
||||
@Nullable String attributionTagFilter, @AppOpsManager.OpFlags int flagsFilter) {
|
||||
if ((filter & FILTER_BY_ATTRIBUTION_TAG) != 0) {
|
||||
ArrayMap<String, List<DiscreteOpEvent>> attributedOps = new ArrayMap<>();
|
||||
attributedOps.put(attributionTagFilter,
|
||||
getOrCreateDiscreteOpEventsList(attributionTagFilter));
|
||||
mAttributedOps = attributedOps;
|
||||
}
|
||||
|
||||
int nTags = mAttributedOps.size();
|
||||
for (int i = nTags - 1; i >= 0; i--) {
|
||||
String tag = mAttributedOps.keyAt(i);
|
||||
List<DiscreteOpEvent> list = mAttributedOps.valueAt(i);
|
||||
list = filterEventsList(list, beginTimeMillis, endTimeMillis, flagsFilter);
|
||||
mAttributedOps.put(tag, list);
|
||||
if (list.size() == 0) {
|
||||
mAttributedOps.removeAt(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void addDiscreteAccess(@Nullable String attributionTag,
|
||||
@AppOpsManager.OpFlags int flags, @AppOpsManager.UidState int uidState,
|
||||
long accessTime, long accessDuration) {
|
||||
List<DiscreteOpEvent> attributedOps = getOrCreateDiscreteOpEventsList(
|
||||
attributionTag);
|
||||
accessTime = Instant.ofEpochMilli(accessTime).truncatedTo(
|
||||
ChronoUnit.MINUTES).toEpochMilli();
|
||||
accessTime = accessTime / TIMELINE_QUANTIZATION * TIMELINE_QUANTIZATION;
|
||||
|
||||
int nAttributedOps = attributedOps.size();
|
||||
for (int i = nAttributedOps - 1; i >= 0; i--) {
|
||||
DiscreteOpEvent previousOp = attributedOps.get(i);
|
||||
if (i == nAttributedOps - 1 && previousOp.mNoteTime == accessTime
|
||||
&& accessDuration > -1) {
|
||||
// existing event with updated duration
|
||||
attributedOps.remove(i);
|
||||
break;
|
||||
}
|
||||
int i = nAttributedOps;
|
||||
for (; i > 0; i--) {
|
||||
DiscreteOpEvent previousOp = attributedOps.get(i - 1);
|
||||
if (previousOp.mNoteTime < accessTime) {
|
||||
break;
|
||||
}
|
||||
if (previousOp.mOpFlag == flags && previousOp.mUidState == uidState) {
|
||||
return;
|
||||
if (accessDuration != previousOp.mNoteDuration
|
||||
&& accessDuration > TIMELINE_QUANTIZATION) {
|
||||
break;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
attributedOps.add(new DiscreteOpEvent(accessTime, accessDuration, uidState, flags));
|
||||
attributedOps.add(i, new DiscreteOpEvent(accessTime, accessDuration, uidState, flags));
|
||||
}
|
||||
|
||||
private List<DiscreteOpEvent> getOrCreateDiscreteOpEventsList(String attributionTag) {
|
||||
@@ -633,18 +745,11 @@ final class DiscreteRegistry {
|
||||
}
|
||||
}
|
||||
|
||||
void deserialize(TypedXmlPullParser parser, long beginTimeMillis, long endTimeMillis,
|
||||
@AppOpsManager.HistoricalOpsRequestFilter int filter,
|
||||
@Nullable String attributionTagFilter,
|
||||
@AppOpsManager.OpFlags int flagsFilter) throws Exception {
|
||||
void deserialize(TypedXmlPullParser parser, long beginTimeMillis) throws Exception {
|
||||
int outerDepth = parser.getDepth();
|
||||
while (XmlUtils.nextElementWithin(parser, outerDepth)) {
|
||||
if (TAG_TAG.equals(parser.getName())) {
|
||||
String attributionTag = parser.getAttributeValue(null, ATTR_TAG);
|
||||
if ((filter & FILTER_BY_ATTRIBUTION_TAG) != 0 && !attributionTag.equals(
|
||||
attributionTagFilter)) {
|
||||
continue;
|
||||
}
|
||||
List<DiscreteOpEvent> events = getOrCreateDiscreteOpEventsList(
|
||||
attributionTag);
|
||||
int innerDepth = parser.getDepth();
|
||||
@@ -655,11 +760,7 @@ final class DiscreteRegistry {
|
||||
-1);
|
||||
int uidState = parser.getAttributeInt(null, ATTR_UID_STATE);
|
||||
int opFlags = parser.getAttributeInt(null, ATTR_FLAGS);
|
||||
if ((flagsFilter & opFlags) == 0) {
|
||||
continue;
|
||||
}
|
||||
if ((noteTime + noteDuration < beginTimeMillis
|
||||
&& noteTime > endTimeMillis)) {
|
||||
if (noteTime + noteDuration < beginTimeMillis) {
|
||||
continue;
|
||||
}
|
||||
DiscreteOpEvent event = new DiscreteOpEvent(noteTime, noteDuration,
|
||||
@@ -715,5 +816,41 @@ final class DiscreteRegistry {
|
||||
out.attributeInt(null, ATTR_FLAGS, mOpFlag);
|
||||
}
|
||||
}
|
||||
|
||||
private static List<DiscreteOpEvent> stableListMerge(List<DiscreteOpEvent> a,
|
||||
List<DiscreteOpEvent> b) {
|
||||
int nA = a.size();
|
||||
int nB = b.size();
|
||||
int i = 0;
|
||||
int k = 0;
|
||||
List<DiscreteOpEvent> result = new ArrayList<>(nA + nB);
|
||||
while (i < nA || k < nB) {
|
||||
if (i == nA) {
|
||||
result.add(b.get(k++));
|
||||
} else if (k == nB) {
|
||||
result.add(a.get(i++));
|
||||
} else if (a.get(i).mNoteTime < b.get(k).mNoteTime) {
|
||||
result.add(a.get(i++));
|
||||
} else {
|
||||
result.add(b.get(k++));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static List<DiscreteOpEvent> filterEventsList(List<DiscreteOpEvent> list,
|
||||
long beginTimeMillis, long endTimeMillis, @AppOpsManager.OpFlags int flagsFilter) {
|
||||
int n = list.size();
|
||||
List<DiscreteOpEvent> result = new ArrayList<>(n);
|
||||
for (int i = 0; i < n; i++) {
|
||||
DiscreteOpEvent event = list.get(i);
|
||||
if ((event.mOpFlag & flagsFilter) != 0
|
||||
&& event.mNoteTime + event.mNoteDuration > beginTimeMillis
|
||||
&& event.mNoteTime < endTimeMillis) {
|
||||
result.add(event);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -532,7 +532,7 @@ final class HistoricalRegistry {
|
||||
System.currentTimeMillis()).increaseAccessDuration(op, uid, packageName,
|
||||
attributionTag, uidState, flags, increment);
|
||||
mDiscreteRegistry.recordDiscreteAccess(uid, packageName, op, attributionTag,
|
||||
flags, uidState, increment, eventStartTime);
|
||||
flags, uidState, eventStartTime, increment);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user