Merge "Keep track of and persist largest AttributionChainId." into sc-dev
This commit is contained in:
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
package com.android.server.appop;
|
package com.android.server.appop;
|
||||||
|
|
||||||
|
import static android.app.AppOpsManager.ATTRIBUTION_CHAIN_ID_NONE;
|
||||||
import static android.app.AppOpsManager.FILTER_BY_ATTRIBUTION_TAG;
|
import static android.app.AppOpsManager.FILTER_BY_ATTRIBUTION_TAG;
|
||||||
import static android.app.AppOpsManager.FILTER_BY_OP_NAMES;
|
import static android.app.AppOpsManager.FILTER_BY_OP_NAMES;
|
||||||
import static android.app.AppOpsManager.FILTER_BY_PACKAGE_NAME;
|
import static android.app.AppOpsManager.FILTER_BY_PACKAGE_NAME;
|
||||||
@@ -58,7 +59,9 @@ import com.android.internal.util.XmlUtils;
|
|||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
@@ -138,6 +141,7 @@ final class DiscreteRegistry {
|
|||||||
|
|
||||||
private static final String TAG_HISTORY = "h";
|
private static final String TAG_HISTORY = "h";
|
||||||
private static final String ATTR_VERSION = "v";
|
private static final String ATTR_VERSION = "v";
|
||||||
|
private static final String ATTR_LARGEST_CHAIN_ID = "lc";
|
||||||
private static final int CURRENT_VERSION = 1;
|
private static final int CURRENT_VERSION = 1;
|
||||||
|
|
||||||
private static final String TAG_UID = "u";
|
private static final String TAG_UID = "u";
|
||||||
@@ -182,6 +186,16 @@ final class DiscreteRegistry {
|
|||||||
|
|
||||||
DiscreteRegistry(Object inMemoryLock) {
|
DiscreteRegistry(Object inMemoryLock) {
|
||||||
mInMemoryLock = inMemoryLock;
|
mInMemoryLock = inMemoryLock;
|
||||||
|
synchronized (mOnDiskLock) {
|
||||||
|
mDiscreteAccessDir = new File(
|
||||||
|
new File(Environment.getDataSystemDirectory(), "appops"),
|
||||||
|
"discrete");
|
||||||
|
createDiscreteAccessDirLocked();
|
||||||
|
int largestChainId = readLargestChainIdFromDiskLocked();
|
||||||
|
synchronized (mInMemoryLock) {
|
||||||
|
mDiscreteOps = new DiscreteOps(largestChainId);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void systemReady() {
|
void systemReady() {
|
||||||
@@ -190,15 +204,6 @@ final class DiscreteRegistry {
|
|||||||
setDiscreteHistoryParameters(p);
|
setDiscreteHistoryParameters(p);
|
||||||
});
|
});
|
||||||
setDiscreteHistoryParameters(DeviceConfig.getProperties(DeviceConfig.NAMESPACE_PRIVACY));
|
setDiscreteHistoryParameters(DeviceConfig.getProperties(DeviceConfig.NAMESPACE_PRIVACY));
|
||||||
synchronized (mOnDiskLock) {
|
|
||||||
synchronized (mInMemoryLock) {
|
|
||||||
mDiscreteAccessDir = new File(
|
|
||||||
new File(Environment.getDataSystemDirectory(), "appops"),
|
|
||||||
"discrete");
|
|
||||||
createDiscreteAccessDirLocked();
|
|
||||||
mDiscreteOps = new DiscreteOps();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setDiscreteHistoryParameters(DeviceConfig.Properties p) {
|
private void setDiscreteHistoryParameters(DeviceConfig.Properties p) {
|
||||||
@@ -251,7 +256,7 @@ final class DiscreteRegistry {
|
|||||||
DiscreteOps discreteOps;
|
DiscreteOps discreteOps;
|
||||||
synchronized (mInMemoryLock) {
|
synchronized (mInMemoryLock) {
|
||||||
discreteOps = mDiscreteOps;
|
discreteOps = mDiscreteOps;
|
||||||
mDiscreteOps = new DiscreteOps();
|
mDiscreteOps = new DiscreteOps(discreteOps.mChainIdOffset);
|
||||||
mCachedOps = null;
|
mCachedOps = null;
|
||||||
}
|
}
|
||||||
deleteOldDiscreteHistoryFilesLocked();
|
deleteOldDiscreteHistoryFilesLocked();
|
||||||
@@ -275,6 +280,50 @@ final class DiscreteRegistry {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private int readLargestChainIdFromDiskLocked() {
|
||||||
|
final File[] files = mDiscreteAccessDir.listFiles();
|
||||||
|
if (files != null && files.length > 0) {
|
||||||
|
File latestFile = null;
|
||||||
|
long latestFileTimestamp = 0;
|
||||||
|
for (File f : files) {
|
||||||
|
final String fileName = f.getName();
|
||||||
|
if (!fileName.endsWith(DISCRETE_HISTORY_FILE_SUFFIX)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
long timestamp = Long.valueOf(fileName.substring(0,
|
||||||
|
fileName.length() - DISCRETE_HISTORY_FILE_SUFFIX.length()));
|
||||||
|
if (latestFileTimestamp < timestamp) {
|
||||||
|
latestFile = f;
|
||||||
|
latestFileTimestamp = timestamp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (latestFile == null) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
FileInputStream stream;
|
||||||
|
try {
|
||||||
|
stream = new FileInputStream(latestFile);
|
||||||
|
} catch (FileNotFoundException e) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
TypedXmlPullParser parser = Xml.resolvePullParser(stream);
|
||||||
|
XmlUtils.beginDocument(parser, TAG_HISTORY);
|
||||||
|
|
||||||
|
final int largestChainId = parser.getAttributeInt(null, ATTR_LARGEST_CHAIN_ID, 0);
|
||||||
|
return largestChainId;
|
||||||
|
} catch (Throwable t) {
|
||||||
|
return 0;
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
stream.close();
|
||||||
|
} catch (IOException e) { }
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void readDiscreteOpsFromDisk(DiscreteOps discreteOps) {
|
private void readDiscreteOpsFromDisk(DiscreteOps discreteOps) {
|
||||||
synchronized (mOnDiskLock) {
|
synchronized (mOnDiskLock) {
|
||||||
long beginTimeMillis = Instant.now().minus(sDiscreteHistoryCutoff,
|
long beginTimeMillis = Instant.now().minus(sDiscreteHistoryCutoff,
|
||||||
@@ -301,7 +350,7 @@ final class DiscreteRegistry {
|
|||||||
void clearHistory() {
|
void clearHistory() {
|
||||||
synchronized (mOnDiskLock) {
|
synchronized (mOnDiskLock) {
|
||||||
synchronized (mInMemoryLock) {
|
synchronized (mInMemoryLock) {
|
||||||
mDiscreteOps = new DiscreteOps();
|
mDiscreteOps = new DiscreteOps(0);
|
||||||
}
|
}
|
||||||
clearOnDiskHistoryLocked();
|
clearOnDiskHistoryLocked();
|
||||||
}
|
}
|
||||||
@@ -341,6 +390,10 @@ final class DiscreteRegistry {
|
|||||||
: new String[]{AppOpsManager.opToPublicName(dumpOp)};
|
: new String[]{AppOpsManager.opToPublicName(dumpOp)};
|
||||||
discreteOps.filter(0, Instant.now().toEpochMilli(), filter, uidFilter, packageNameFilter,
|
discreteOps.filter(0, Instant.now().toEpochMilli(), filter, uidFilter, packageNameFilter,
|
||||||
opNamesFilter, attributionTagFilter, OP_FLAGS_ALL);
|
opNamesFilter, attributionTagFilter, OP_FLAGS_ALL);
|
||||||
|
pw.print(prefix);
|
||||||
|
pw.print("Largest chain id: ");
|
||||||
|
pw.print(mDiscreteOps.mLargestChainId);
|
||||||
|
pw.println();
|
||||||
discreteOps.dump(pw, sdf, date, prefix, nDiscreteOps);
|
discreteOps.dump(pw, sdf, date, prefix, nDiscreteOps);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -351,14 +404,14 @@ final class DiscreteRegistry {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private DiscreteOps getAllDiscreteOps() {
|
private DiscreteOps getAllDiscreteOps() {
|
||||||
DiscreteOps discreteOps = new DiscreteOps();
|
DiscreteOps discreteOps = new DiscreteOps(0);
|
||||||
|
|
||||||
synchronized (mOnDiskLock) {
|
synchronized (mOnDiskLock) {
|
||||||
synchronized (mInMemoryLock) {
|
synchronized (mInMemoryLock) {
|
||||||
discreteOps.merge(mDiscreteOps);
|
discreteOps.merge(mDiscreteOps);
|
||||||
}
|
}
|
||||||
if (mCachedOps == null) {
|
if (mCachedOps == null) {
|
||||||
mCachedOps = new DiscreteOps();
|
mCachedOps = new DiscreteOps(0);
|
||||||
readDiscreteOpsFromDisk(mCachedOps);
|
readDiscreteOpsFromDisk(mCachedOps);
|
||||||
}
|
}
|
||||||
discreteOps.merge(mCachedOps);
|
discreteOps.merge(mCachedOps);
|
||||||
@@ -368,9 +421,13 @@ final class DiscreteRegistry {
|
|||||||
|
|
||||||
private final class DiscreteOps {
|
private final class DiscreteOps {
|
||||||
ArrayMap<Integer, DiscreteUidOps> mUids;
|
ArrayMap<Integer, DiscreteUidOps> mUids;
|
||||||
|
int mChainIdOffset;
|
||||||
|
int mLargestChainId;
|
||||||
|
|
||||||
DiscreteOps() {
|
DiscreteOps(int chainIdOffset) {
|
||||||
mUids = new ArrayMap<>();
|
mUids = new ArrayMap<>();
|
||||||
|
mChainIdOffset = chainIdOffset;
|
||||||
|
mLargestChainId = chainIdOffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean isEmpty() {
|
boolean isEmpty() {
|
||||||
@@ -378,6 +435,7 @@ final class DiscreteRegistry {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void merge(DiscreteOps other) {
|
void merge(DiscreteOps other) {
|
||||||
|
mLargestChainId = max(mLargestChainId, other.mLargestChainId);
|
||||||
int nUids = other.mUids.size();
|
int nUids = other.mUids.size();
|
||||||
for (int i = 0; i < nUids; i++) {
|
for (int i = 0; i < nUids; i++) {
|
||||||
int uid = other.mUids.keyAt(i);
|
int uid = other.mUids.keyAt(i);
|
||||||
@@ -390,6 +448,17 @@ final class DiscreteRegistry {
|
|||||||
@Nullable String attributionTag, @AppOpsManager.OpFlags int flags,
|
@Nullable String attributionTag, @AppOpsManager.OpFlags int flags,
|
||||||
@AppOpsManager.UidState int uidState, long accessTime, long accessDuration,
|
@AppOpsManager.UidState int uidState, long accessTime, long accessDuration,
|
||||||
@AppOpsManager.AttributionFlags int attributionFlags, int attributionChainId) {
|
@AppOpsManager.AttributionFlags int attributionFlags, int attributionChainId) {
|
||||||
|
if (attributionChainId != ATTRIBUTION_CHAIN_ID_NONE) {
|
||||||
|
attributionChainId += mChainIdOffset;
|
||||||
|
if (attributionChainId < 0) {
|
||||||
|
attributionChainId -= mChainIdOffset;
|
||||||
|
mChainIdOffset = 0;
|
||||||
|
mLargestChainId = attributionChainId;
|
||||||
|
}
|
||||||
|
if (attributionChainId > mLargestChainId) {
|
||||||
|
mLargestChainId = attributionChainId;
|
||||||
|
}
|
||||||
|
}
|
||||||
getOrCreateDiscreteUidOps(uid).addDiscreteAccess(op, packageName, attributionTag, flags,
|
getOrCreateDiscreteUidOps(uid).addDiscreteAccess(op, packageName, attributionTag, flags,
|
||||||
uidState, accessTime, accessDuration, attributionFlags, attributionChainId);
|
uidState, accessTime, accessDuration, attributionFlags, attributionChainId);
|
||||||
}
|
}
|
||||||
@@ -442,6 +511,7 @@ final class DiscreteRegistry {
|
|||||||
out.startDocument(null, true);
|
out.startDocument(null, true);
|
||||||
out.startTag(null, TAG_HISTORY);
|
out.startTag(null, TAG_HISTORY);
|
||||||
out.attributeInt(null, ATTR_VERSION, CURRENT_VERSION);
|
out.attributeInt(null, ATTR_VERSION, CURRENT_VERSION);
|
||||||
|
out.attributeInt(null, ATTR_LARGEST_CHAIN_ID, mLargestChainId);
|
||||||
|
|
||||||
int nUids = mUids.size();
|
int nUids = mUids.size();
|
||||||
for (int i = 0; i < nUids; i++) {
|
for (int i = 0; i < nUids; i++) {
|
||||||
@@ -476,8 +546,13 @@ final class DiscreteRegistry {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void readFromFile(File f, long beginTimeMillis) {
|
private void readFromFile(File f, long beginTimeMillis) {
|
||||||
|
FileInputStream stream;
|
||||||
|
try {
|
||||||
|
stream = new FileInputStream(f);
|
||||||
|
} catch (FileNotFoundException e) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
FileInputStream stream = new FileInputStream(f);
|
|
||||||
TypedXmlPullParser parser = Xml.resolvePullParser(stream);
|
TypedXmlPullParser parser = Xml.resolvePullParser(stream);
|
||||||
XmlUtils.beginDocument(parser, TAG_HISTORY);
|
XmlUtils.beginDocument(parser, TAG_HISTORY);
|
||||||
|
|
||||||
@@ -487,7 +562,6 @@ final class DiscreteRegistry {
|
|||||||
if (version != CURRENT_VERSION) {
|
if (version != CURRENT_VERSION) {
|
||||||
throw new IllegalStateException("Dropping unsupported discrete history " + f);
|
throw new IllegalStateException("Dropping unsupported discrete history " + f);
|
||||||
}
|
}
|
||||||
|
|
||||||
int depth = parser.getDepth();
|
int depth = parser.getDepth();
|
||||||
while (XmlUtils.nextElementWithin(parser, depth)) {
|
while (XmlUtils.nextElementWithin(parser, depth)) {
|
||||||
if (TAG_UID.equals(parser.getName())) {
|
if (TAG_UID.equals(parser.getName())) {
|
||||||
@@ -498,8 +572,12 @@ final class DiscreteRegistry {
|
|||||||
} catch (Throwable t) {
|
} catch (Throwable t) {
|
||||||
Slog.e(TAG, "Failed to read file " + f.getName() + " " + t.getMessage() + " "
|
Slog.e(TAG, "Failed to read file " + f.getName() + " " + t.getMessage() + " "
|
||||||
+ Arrays.toString(t.getStackTrace()));
|
+ Arrays.toString(t.getStackTrace()));
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
stream.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -209,6 +209,7 @@ final class HistoricalRegistry {
|
|||||||
mMode = other.mMode;
|
mMode = other.mMode;
|
||||||
mBaseSnapshotInterval = other.mBaseSnapshotInterval;
|
mBaseSnapshotInterval = other.mBaseSnapshotInterval;
|
||||||
mIntervalCompressionMultiplier = other.mIntervalCompressionMultiplier;
|
mIntervalCompressionMultiplier = other.mIntervalCompressionMultiplier;
|
||||||
|
mDiscreteRegistry = other.mDiscreteRegistry;
|
||||||
}
|
}
|
||||||
|
|
||||||
void systemReady(@NonNull ContentResolver resolver) {
|
void systemReady(@NonNull ContentResolver resolver) {
|
||||||
|
|||||||
Reference in New Issue
Block a user